• Thread类及常见方法


    在这里插入图片描述

    一、Thread常见构造方法

    Thread类是JVM用来管理线程的一个类,每个线程都有唯一一个Thread对象与之对应,JVM会将这些对象组织起来,线程调度,线程管理。
    在这里插入图片描述

    方法说明
    Thread()创建线程对象
    Thread(Runnable target使用Runnable对象创建线程对象
    Thread(String name)创建线程对象,并命名
    Thread(Runnable target,String name)使用Runnable对象创建线程,并命名

    我们在创建Thread的对象为什么要命名?方便我们查看信息和调试。
    在这里插入图片描述
    线程默认名叫做Thread-0, Thread-1等等,当线程比较多的时候,很难分辨线程,所以我们可以命名。

    二、Thread常见属性

    属性获取方法
    IDgetId()
    名称getName()
    状态getState()
    优先级getPriority()
    是否有后台线程isDaemon()
    是否存活isAlive()
    是否被中断isInterrupted()

    getId(): ID是线程的唯一标识,不同的线程不重复

    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("Hello world!");
        }
    }
    public class ThreadDemo {
        public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.getId());
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    getName: 名称是我们构造方法设置的名称,如果没有设置,那就是默认名。

    public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.getName());
        }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    因为我们没有命名,所以使用的是默认名。
    getState(): 指的是当前线程所处的状态 ( java当中的线程状态比操作系统中的状态更丰富,分的更细 ).

    public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.getState());
        }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    这里NEW状态 (指的是线程对象已创建,但操作系统还没有为其分配PCB) 是什么大家先不用管,后面我们会详细介绍,只需要知道getState()方法是用来查看线程状态的。
    getPriority: 我们可以获取当前线程的优先级,但没有太大的用,实际还得取决于操作系统内核的具体调度。

    public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.getPriority());
        }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    isDaemon(): 是否为守护线程(也叫后台线程), 简单的理解一下,我们手动创建的线程都是前台线程,JVM自带的线程都是后台线程,我们也可以通过setDaemon()方法将前台线程设置为后台线程。
    在这里插入图片描述

    public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.isDaemon());
        }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    isAlive(): 线程的run方法是否执行结束。
    在这里插入图片描述

    如果我们只创建了一个t变量,我们并没有在操作系统内核里有线程,只是把我们线程执行的任务梳理好了
    在这里插入图片描述
    当我们执行了start()方法后,就会让内核创建一个PCB,此时这个PCB才表示一个真正的线程。
    调用start()方法之前,isAlive()是false
    调用start()方法之后,run()方法未执行完,isAlive()为false.

    public static void main(String[] args) {
            Thread t = new MyThread();
            System.out.println(t.isAlive());
            t.start();
            System.out.println(t.isAlive());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    **isInterrupt(): ** 线程中断问题
    这两个方法我们后面会进一步说明。

    三、Thread常见方法

    start()

    start() 启动一个线程。

    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("Hello world!");
        }
    }
    public class ThreadDemo {
        public static void main(String[] args) {
            Thread t = new MyThread();
            t.start();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    run()方法提供线程要做的事情的指令清单。
    在这里插入图片描述
    这是创建t对象,只是知道要找那样的线程做什么事
    在这里插入图片描述
    只有当start(),操作系统内核才会创建一个真真正正的线程PCB,然后去调用run()方法。

    获取当前线程

    方法说明
    currentThread()获取当前线程对象的引用

    在这里插入图片描述
    我们可以发现currentThread()方法是Thread类下的一个静态方法,所以我们直接使用类名调用即可。

    休眠当前线程

    方法说明
    sleep(long millis)休眠当前线程millis毫秒

    由于线程调度是不可控的,我们sleep()方法的实际休眠是大于等于设置的时间的。

    在这里插入图片描述
    我们的sleep方法也是Thread下的静态方法,直接类名调用即可。
    需要注意的是我们在那个线程下面调用该方法,那个线程休眠。
    在这里插入图片描述
    使用sleep时会有一个中断异常(非受查异常),需要我们手动抛出。

    public static void main(String[] args) throws InterruptedException {
            System.out.println(System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(System.currentTimeMillis());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们直接在主线程演示一下该方法。
    在这里插入图片描述

    中断线程

    线程中断: 我们这里的中断,并不是线程立即就结束了,而是通知该线程,你应该结束了,但实际是否结束,取决于线程里具体的代码。
    1.使用标志位来控制线程是否结束

    public class ThreadDemo {
        private static boolean flg = true;
    
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                while (flg) {
                    System.out.println("My Thread!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
            Thread.sleep(3000);
            flg = false;
        }
    }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    在这里插入图片描述
    我们这个代码之所以能够起到修改flg就使线程结束,完全取决于线程内部的代码书写,我们只能起到一个通知作用,至于是否结束,还是取决于线程内部,即使我们sleep正在休眠,我们的标志位也可以唤醒sleep。

    2. 调用 interrupt() 方法来通知

    public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("My Thread!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
            Thread.sleep(3000);
            t.interrupt();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    在这里插入图片描述
    我们可以发现我们的代码触发了异常。
    在这里插入图片描述
    在唤醒sleep之后,我们的线程还在一直执行
    在这里插入图片描述
    interrupt()方法会做两件事:
    1.把线程内部的标志位设置为true
    2.如果线程正在sleep,会触发异常,将sleep唤醒。
    sleep唤醒的同时,会清空标志位,将刚才设置的标志位在设置为false(这就导致,我们的循环会继续执行).
    如果我们想去中断,我们可以在异常里加一个break。当我们sleep被唤醒时,结束run()方法。
    在这里插入图片描述
    在这里插入图片描述

    这里再一次证明了,这里的中断只是通知线程,至于是否执行还得看线程内部的代码。

    join()

    join(): 等待一个线程
    因为我们线程是随即调度的过程,线程的执行顺便我们无法把控,但在一些场景下我们需要有明确的线程程序顺序,等待线程,就是可以控制两个线程的结束顺序。

    方法说明
    join()等待线程结束
    join(long millis)等待线程结束,最多等millis毫秒
    public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                for (int i = 0; i < 3; i++) {
                    System.out.println("My Thread!");
                }
            });
            t.start();
            System.out.println("Main!");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    我们想让t线程先执行完,再去打印Main!

    public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                for (int i = 0; i < 3; i++) {
                    System.out.println("My Thread!");
                }
            });
            t.start();
            t.join();
            System.out.println("Main!");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    我们在主线程调用了下join()方法。
    在这里插入图片描述

  • 相关阅读:
    第十五章 类和对象——友元
    【图解HTTP】返回结果的HTTP状态码
    【Unity基础】1.项目搭建与视图编辑
    Spring版本特性--->Spring各个版本引入了哪些新特性?-1
    移动端安全攻防那些事儿,看这场直播就够了!
    【汽修帮手】数据采集,爬虫,根据pdf文件流合并pdf文件
    189. 轮转数组
    vscode用r无法读取文件
    Docker Compose映射卷的作用是什么,dockerfile这个文件有什么区别和联系?
    从一次数据库误操作开始了解MySQL日志【bin log、redo log、undo log】
  • 原文地址:https://blog.csdn.net/buhuisuanfa/article/details/128199387