自学内容网 自学内容网

多线程基础保姆级教程

中断一个线程

在这里插入图片描述

通常使用Thread.currentThread().isInterrupted() t.isInterrupted()配合使用来中断一个线程
currentThread()方法用来获取当前线程的是咧,哪个线程调用就返回哪个线程的对象。
Thread内部有一个标志位,这个标志位就可以用来判断线程是否结束
上篇讲到了,手动设置标志位,当线程内部在sleep的时候,主线程修改变量,新线程不能及时响应
而t.interrupt()就可以把Thread内部的这个标志位设置位true,及时线程内部的逻辑出现阻塞(sleep),也是可以用这个方法唤醒的。
正常来说,sleep会休眠到时间到,才能唤醒。此处给出的interrupt就可以使sleep内部触发一个异常,从而提前被唤醒。而我们自己设置的标志位无法实现这个效果。
例子

在这里插入代码package thread;

public class Demo001 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            //Thread头部有一个现成的标志位,可以用来判定当前循环是否结束
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("线程工作中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        });
        t.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("让t终止");
        t.isInterrupted();
    }
}

运行结果
在这里插入图片描述
运行结果显示,异常确实是出现了,sleep确实唤被醒了,但是上述t仍然在继续工作!!并没真正结束!!!
interrupt()虽然唤醒线程了,此时sleep()方法会抛出异常,同时会自动清除刚才设置的标志位。这样就使得 设置标志位这样的效果好像没生效一样。
为啥这么设定??
java这样设定是期望,当线程收到 要中断 这样的信号时候,它能够自由决定,接下来该怎么处理?
小例子:
有一天,我正在打游戏,我吗让我下楼买瓶酱油
当我收到这个信号,就有三种做法
1.直接丢下游戏,去买酱油
2.我把这局打完再去
3.直接忽略,假装没听见
同样的线程也可以采取这三种方式来执行
这样的目的是为了让线程有更多的 可操作空间。而这种可操作空间的前提是通过异常(异常可以清楚设置好的标志位,从而给了线程更多可操作的空间)。如果没有sleep(),没有抛出异常,就没有上述的可操作空间。

线程等待

在这里插入图片描述

join()方法是让一个线程等待另一个线程执行结束再继续执行,一般来说,等待操作都是要有一个超时时间的。本质上就是控制线程的执行顺序

t.join()的工作过程
(1)如果t线程正在运行,此时调用join的线程就会阻塞,一直阻塞到t线程执行结束为止
(2)如果t1线程已经执行结束了,此时调用join线程,就直接返回了,不会涉及到阻塞

public void join(long millis) 最多等 millis 毫秒,
public void join(long millis, int nanos) 同理,但可以更高精度
实际开发中一般不建议死等,最好要带有"超时时间"

获取当前线程引用

在这里插入图片描述
例子

public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
   }
}

休眠当前线程

在这里插入图片描述

注意:因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的。 例如:sleep(1000),
系统会按照1000这个时间来控制让线程休眠 但是当1000时间到了之后,系统会唤醒这个线程.(阻塞->就绪)
但是不是说这个线程成了就绪状态,就能立即回到cpu上运行??(这中间有一个“调度”开销)
对于windows或者linux这样的系统来说,调度开销很大,可能达到ms级别.
有些场景,可能对于时间精度要求是很高的比如,发射卫星;或者导弹拦截 往往需要使用"实时操作系统",任务调度的开销在一定时间范围之内.
为了实时,也有很多的限制,功能上是不如windows和linux的.

观察线程的所有状态

线程的状态是一个枚举类型 Thread.State

public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
       }
   }
}

线程状态和状态转移的意义

在这里插入图片描述
大家不要被这个状态转移图吓到,我们重点是要理解状态的意义以及各个状态的具体意思。

NEW:Thread对象已经有了.start方法还没调用
TERMINATED:Thread对象还在,内核中的线程已经没了.
RUNNABLE:就绪状态(线程已经在cpu上执行了/线程正在排队等待上cpu执行)
TIMED_WAITING:阻塞.由于sleep这种固定时间的方式产生的阻塞
WAITING:阻塞.由于wait这种不固定时间的方式产生的阻塞
BLOCKED:阻塞.由于锁竞争导致的阻塞
注意:
BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.
TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒


原文地址:https://blog.csdn.net/m0_74701193/article/details/142531647

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!