JAVA-Thread类实现多线程

引言:

本章博客涉及进程线程内容,如果不了解的可以看:什么是进程线程-CSDN博客
线程是操作系统的概念,操作系统提供的API供程序员使用操作。但是不同的操作系统(Winodws、Linux、Unix......差别很大),但是做为JAVA程序员就不需要担心了,JVM把这些封装好了。我们不需要关注系统原生API,只需要学习java提供的这一套API就可以了。

一、创建线程的几种方法

1.继承Thread类

java 复制代码
//1.自己创建一个类,去继承 Thread类 并重写run方法
class MyThread extends Thread{
    //2.线程会自动调用run方法中的内容,类似主线程中的main方法
    @Override
    public void run() {
        while (true) {
            System.out.println("hello thread");
        }
    }
}


public class demo1 {
    public static void main(String[] args) {
        //3.实例化继承了Thread的类
        MyThread myThread = new MyThread();
        //4.创建线程
        myThread.start();

        while (true) {
            System.out.println("hello main");
        }
    }
}

结果就会不停打印:hello main 和 hello thread

但是不方便观察而且,我电脑的风扇已经转起来了,因为相当于同时执行两个程序,并且死循环那么它的执行就非常的快。我们可以加上sleep(休眠),第一让线程休息指定时间,第二方便我们观察。

1.1 Thread.sleep()

传入的单位是毫秒(ms),sleep会让出CPU资源,不再争抢CPU资源

而且sleep还是静态的方法,我们直接使用类名调用。

sleep抛出异常问题:

如果是继承Thread的类,不能使用throws向上抛,因为Thread类中没有处理这个异常,我们只能使用try catch处理掉这个异常:

在主函数中的sleep:

在主函数中的sleep使用throws 和 try catch都是可以的,如果使用throwsJVM会处理这个异常,主函数中可以用 throws 处理 Thread.sleep() 方法抛出的 InterruptedException 异常,JVM 会处理这个被抛出的异常,具体表现为打印异常堆栈信息和终止程序执行。

java 复制代码
//1.自己创建一个类,去继承 Thread类 并重写run方法
class MyThread extends Thread{
    //2.线程会自动调用run方法中的内容,类似主线程中的main方法
    @Override
    public void run() {
        while (true) {
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}


public class demo1 {
    public static void main(String[] args) throws InterruptedException {
        //3.实例化继承了Thread的类
        MyThread myThread1 = new MyThread();
        //4.创建线程
        myThread1.start();

        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}

结果:

1.2 start()

start方法是创建线程的方法,底层会调用对应操作系统的API来创建线程。

1.3 run()

run()会被创建的线程自动调用,理解为另一个执行线程任务的入口,就像是JVM调用main方法一样。

2.实现Runnable接口

Thrad实现了Runnable接口:

Runnable接口是函数式接口,意味着我们还可以通过Lambda表达式来写。我们先用普通的方式写:

java 复制代码
//1.定义一个类实现Runnable接口
class MyRunnable implements Runnable {
    //2.实现run方法
    @Override
    public void run() {
        while (true) {
            System.out.println("hello MyRunnable");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


public class demo2 {
    
    public static void main(String[] args) throws InterruptedException{
        //3.实例化实现Runnable的接口
        MyRunnable runnable = new MyRunnable();
        //4.把Runnable的接口给Thread
        Thread t = new Thread(runnable);
        //5.创建线程
        t.start();

        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }

    }
}

记得是先实例化实现Runnable的类,在实例化Thread类的时候,把实现了Runnable接口的类传入构造方法中。

结果:


为什么在Thread对象的时候可以传入Thread,肯定是有这样的一个构造方法,我们现在来了解一下Thread的构造方法。

2.1 Thread的构造方法

|-----------------------------------------------|-------------------------------|
| 方法 | 说明 |
| Thread() | 创建线程对象 |
| Thread(Runnable target) | 使用Runnable子类对象创建线程对象 |
| Thread(String name) | 创建线程对象,并给线程取名字 |
| Thread(Runnable target, String name) | 使用Runnable子类对象创建线程对象,并给线程命名 |
| 【了解】Thread(ThreadGroup group,Runnable target) | 线程可以被用来分组管理,分好的组即为线这个目前我们了解即可 |

后面我会教两种方式观察线程,到时候就可以观察到,给线程的命名。

后面的实现多线程的本质都是上面两种方法。

3.使用匿名内部类来继承Thread类

本质就是第一种方法

java 复制代码
public class demo3 {
    public static void main(String[] args) throws InterruptedException {
        //1.使用匿名内部类来继承Thread方法
        Thread t = new Thread() {
            //2.重写run方法
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello run");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        //3.创建线程
        t.start();

        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }


    }
}

结果:

4.在创建Thread对象的时候传入,实现Runnable的接口

本质是第二种方法

java 复制代码
public class demo4 {

    public static void main(String[] args) throws InterruptedException {
        //1.在创建Thread对象的时候,传入实现Runnable的匿名内部类
        Thread t = new Thread(new Runnable() {
            //2.重写run方法
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        //3.掉用线程
        t.start();

        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }

    }
}

5.Lambda表达式实现Runnable

不了解Lambda的可以看我这篇文章

JAVA-Lambda表达式(高质量)-CSDN博客

本质也是第二种方式

java 复制代码
public class demo8 {

    public static void main(String[] args) throws InterruptedException {
        //1.实例化Thread对象时,传入实现了Runnable的匿名内部类
        Thread thread = new Thread(() -> {

            while (true) {
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();

        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }


    }
}

结果:

更具第一种和第二种方式,其实还可以创建出好多种,这里就不一一举例了,每一种方式都很重要,都需要理解。

二、观察线程

1.方式一

双击打开jconsole文件 ,程序必须是在运行的情况下

点击连接

选择不安全的连接

选择线程

用这个观察非常有用,以后程序多了就需要要用到这样的工具

2.方式二

打断点开始调试

这里的线程默认命名也是Thread-?

如果我自己定义一个名字:

相关推荐
Z9fish5 分钟前
sse哈工大C语言编程练习20
c语言·开发语言·算法
CodeCaptain6 分钟前
nacos-2.3.2-OEM与nacos3.1.x的差异分析
java·经验分享·nacos·springcloud
萧鼎30 分钟前
Python 包管理的“超音速”革命:全面上手 uv 工具链
开发语言·python·uv
Anastasiozzzz1 小时前
Java Lambda 揭秘:从匿名内部类到底层原理的深度解析
java·开发语言
骇客野人1 小时前
通过脚本推送Docker镜像
java·docker·容器
刘琦沛在进步1 小时前
【C / C++】引用和函数重载的介绍
c语言·开发语言·c++
机器视觉的发动机1 小时前
AI算力中心的能耗挑战与未来破局之路
开发语言·人工智能·自动化·视觉检测·机器视觉
铁蛋AI编程实战1 小时前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
HyperAI超神经1 小时前
在线教程|DeepSeek-OCR 2公式/表格解析同步改善,以低视觉token成本实现近4%的性能跃迁
开发语言·人工智能·深度学习·神经网络·机器学习·ocr·创业创新
晚霞的不甘1 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频