当前位置: 首页 > article >正文

多线程基础保姆级教程

多线程基础

    • 中断一个线程
    • **线程等待**
    • 获取当前线程引用
    • 休眠当前线程
    • 观察线程的所有状态
    • 线程状态和状态转移的意义

中断一个线程

在这里插入图片描述

通常使用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 线程在无限等待唤醒


http://www.kler.cn/a/354058.html

相关文章:

  • C#WPF基础介绍/第一个WPF程序
  • JDK高频面试题(包重点)
  • Excel将混乱的多行做成1列
  • 面试经典 150 题——数组/字符串(一)
  • 【QED】等式构造
  • 【Three.js基础学习】33.Halftone Shading shaders
  • Springboot连接多数据库
  • GPT-SoVITS的批量克隆声音并且合并
  • R语言机器学习算法实战系列(五)GBM算法+SHAP值 (Gradient Boosting Machines)
  • plsql查询Oracle数据库发现有的数据是乱码
  • Pr 音频效果快速参考(合集 · 2025版)
  • 基于Leaflet和SpringBoot的全球国家综合检索WebGIS可视化
  • 阿里 C++面试,算法题没做出来,,,
  • 基于STM32的智能物联网家用机器人设计
  • 组串式储能变流升压一体机
  • Field injection is not recommended – Spring IOC
  • AutoCompleteTextView
  • 【SuperHotSwap】IDEA零配置热更新插件升级
  • 【设计模式】深入理解Python中的原型设计模式
  • 【电商购物管理系统】Python+Django网页界面平台+商品管理+数据库
  • Unity3D模型消融方法(二)
  • vue中如何自定义Form表单rules校验方法(手机号/座机号、身份证号/社会统一信代码校验,支持多个,以英文逗号分隔)
  • Scala的filter函数
  • 网络基础一
  • 利用高德API获取整个城市的公交路线并可视化(五)
  • Promise.race()