• 关于Thread 类及其基本用法


            Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。 要想知道Thread类的基本用法,首先得知道如何创建Thread类,创建Thread类的方法大抵有多种,这里简单的举例比较常用的。

    1)继承Thread类,然后像创建普通类一样创建Thread类。

    2)实现 Runnable 接口,创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数.

    3)匿名内部类创建 Thread 子类对象

    4)匿名内部类创建 Runnable 子类对象

    5)lambda 表达式创建 Runnable 子类对象

    class Student extends Thread{
        @Override
        public void run() {
            System.out.println("haha1");
        }
    }
    class Teacher implements Runnable{
        @Override
        public void run() {
            System.out.println("haha2");
        }
    }
    public class Test2 {
        public static void main(String[] args) {
            Student student = new Student();//方法1
            student.start();
            Thread thread2 = new Thread(new Teacher());//方法2
            thread2.start();
            Thread thread3 = new Thread(){
                @Override
                public void run() {
                    System.out.println("haha3");
                }
            };//方法3
            thread3.start();
            Thread thread4 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("haha4");
                }
            });//方法4
            thread4.start();
            Thread thread5 = new Thread(() -> {
                System.out.println("haha5");
            });//方法5
            thread5.start();
        }
    }

    当知道Thread类被创建后,就得知道如何使用Thread类了,首先得知道,start()方法,start()被调用才能创建线程,我们重写的方法run()只是将要被线程执行的逻辑罢了,其次则是Thread的构造方法,从上面的如何创建Thread类,就可以了解到几个Thread的构造方法,首先是典型的没有任何参数的构造方法,方法一和方法三就是,然后则是使用 Runnable 对象创建线程对象 ,方法二,四,五就是(Thread(Runnable target)),当然还有给线程命名的构造方法,毕竟没有给线程命名的话,这调用和调试起来也不太方便(Thread类的对象名不是线程名)(Thread(String name)),最后则是使用 Runnable 对象创建线程对象并且顺便给线程命名的构造方法(Runnable target, String name),这里只说四个并不只有四个,只是其他方法运用较少,这里不做讨论。

            然后则是Thread的常见属性了,Thread的属性较多,这里只做几个较为重要的属性认识。

    1)ID:ID 是线程的唯一标识,不同线程不会重复,其获取方法为通过Thread类的对象来获取。

    Thread thread6 = new Thread(() -> {
        System.out.println("hehe");
    });
    thread6.getId();
    

    2)名称:名称是各种调试工具用到,其可以为自己通过创建Thread对象时给的名称name(Thread(String name)),也可以是不给名称由系统默认取名。获取方法为:

    thread6.getName();

    3)状态:则是线程当前处于的状态,是已完成,还是已创建但没有启动,亦或者是已启动但还没完成的状态等。获取方法则为:

    thread6.getState();

    4)优先级:事情有轻重缓急,进程也一样,理论上优先级高的线程更容易被调度。获取方法为:

    thread6.getPriority();

    5)是否为后台线程:关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。获取方法为:

    thread6.isDaemon();

    6)是否存活:run 方法是否运行结束了,获取方法为:

    thread6.isAlive();

    7)是否被中断:线程的中断问题,下面我们进一步说明,获取方法为:

    thread6.isInterrupted();

    关于中断线程,若一个线程已经启动起来了,该怎样让它停下来呢?

    目前常见的有以下两种方式:
    1. 通过共享的标记来进行沟通
    2. 调用 interrupt() 方法来通知
    首先是1,怎么通过共享的标记进行沟通呢?,及通过一个变量的变化,来操纵线程里的判断,使之尽早执行完run()。
    public static int n = 3;
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (n != 0){
                ;
            }
            System.out.println("haha");
        });
        thread.start();
        n = 0;
    }

    其次则是2,使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.其Thread.currentThread()表示获取当前的线程,isInterrupted()则可以认为是Thread对象内部提供了一个标志位(bonlean),而isInterrupted()则是获取当前标志位,默认为false,倘若要修改标志位的话,只需要使用Interrupted()方法。

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("haha");
            }
        });
        thread.start();
        sleep(1000);
        thread.interrupt();
    }

    因此,这里出现的方法也得熟练掌握。

    public void interrupt() :中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
    public static boolean interrupted() :判断当前线程的中断标志位是否设置,调用后清除标志位
    public boolean isInterrupted():判断对象关联的线程的标志位是否设置,调用后不清除标志位
    thread 收到通知的方式有两种:
    1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通 知,清除中断标志
    当出现 InterruptedException 的时候 , 要不要结束线程取决于 catch 中代码的写法 . 可以选择
    忽略这个异常 , 也可以跳出循环结束线程 . 否则,只是内部的一个中断标志被设置,thread 可以通过 Thread.interrupted() 判断当前线程的中断标志被设置 (清除中断标志)Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,(不清除中断标志)
    这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到。
            下面则简单的介绍线程的常用方法:
    1)等待一个线程 -join():当有参数时,则是等待的时长为该参数的毫秒,没有则等待该线程介绍才行,那个对象调用则是等待那个线程。
    thread.join();
    thread.join(1000);
    public void join(long millis, int nanos) ,同理,但可以更高精度
    2)获取当前线程引用 public static Thread currentThread(); 返回当前线程对象的引用
    3)休眠当前线程:sleep():与join的用法相同,但需要参数并且和join()的参数一样, 有一点要记得,因为线程的调度是不可控的,所以,这个方法只能保证实 际休眠时间是大于等于参数设置的休眠时间的。
    至此,关于Thread的简单认识和使用就此结束。
  • 相关阅读:
    Docker - compose容器编排工具 - 搭建一个自己的博客
    C# 使用DocX生成word文档
    虚拟机(三)VMware Workstation 桥接模式下无法上网
    NLP技术如何为搜索引擎赋能
    TPCH_Q4 的分析优化,对子查询中的 Semi-join 优化
    单片机核心/RTOS必备 (ARM汇编)
    原生js的animate()方法详解
    武大50名学生造卫星,南航“00后”学生造火箭,后浪制造未来可期
    试图带你一文搞懂transformer注意力机制(Self-Attention)的本质
    报错与解决 | 应用程序无法启动0x7b mysql
  • 原文地址:https://blog.csdn.net/LTY3301398968/article/details/132783419