多线程基础保姆级教程

多线程基础

中断一个线程

通常使用Thread.currentThread().isInterrupted() t.isInterrupted()配合使用来中断一个线程

currentThread()方法用来获取当前线程的是咧,哪个线程调用就返回哪个线程的对象。

Thread内部有一个标志位,这个标志位就可以用来判断线程是否结束
上篇讲到了,手动设置标志位,当线程内部在sleep的时候,主线程修改变量,新线程不能及时响应

而t.interrupt()就可以把Thread内部的这个标志位设置位true,及时线程内部的逻辑出现阻塞(sleep),也是可以用这个方法唤醒的。

正常来说,sleep会休眠到时间到,才能唤醒。此处给出的interrupt就可以使sleep内部触发一个异常,从而提前被唤醒。而我们自己设置的标志位无法实现这个效果。
例子

java 复制代码
在这里插入代码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) 同理,但可以更高精度

实际开发中一般不建议死等,最好要带有"超时时间"

获取当前线程引用

例子

java 复制代码
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

java 复制代码
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 线程在无限等待唤醒

相关推荐
PP东1 分钟前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
ManThink Technology6 分钟前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
invicinble10 分钟前
springboot的核心实现机制原理
java·spring boot·后端
人道领域18 分钟前
SSM框架从入门到入土(AOP面向切面编程)
java·开发语言
大模型玩家七七39 分钟前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
CodeToGym1 小时前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel
凡人叶枫1 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
JMchen1232 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
阔皮大师2 小时前
INote轻量文本编辑器
java·javascript·python·c#
小法师爱分享2 小时前
StickyNotes,简单便签超实用
java·python