多线程·线程状态


目录

 1.等待一个线程 join

2.休眠当前线程

3.线程的所有状态

4.线程的状态转换 


 1.等待一个线程 join

 有些场景,我们需要控制线程的执行顺序,这时候就需要用到 join

比如:把大象装进冰箱要几步?

第一步:打开冰箱;

第二步:把大象装进去;

第三步:把冰箱关上。

把每一步都当成一个线程来看,那么线程2就要等线程1完成、线程3就等线程2完成。

public class Main {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{System.out.println("打开冰箱");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});Thread t2 = new Thread(()->{System.out.println("把大象装进去");try{Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}});Thread t3 = new Thread(()->{System.out.println("把冰箱关上");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}});t1.start();t1.join();//main线程等待线程t1完成System.out.println("冰箱已经打开了");t2.start();t2.join();//main线程等待线程t2完成System.out.println("大象已经装进去了");t3.start();t3.join();//确保线程t3完成System.out.println("冰箱关上了,任务完成!");}
}

这里 start() 之后,t1main 线程就开始并发执行了,当 main 线程执行到 t1.join() 表示 main 线程得等 t1 线程执行完毕后,才能接着往后执行代码!只要 t1 线程没有执行完毕,main 线程就会发生阻塞,一直阻塞到 t1 线程执行完毕,也就是执行完对应的 run 方法!

像上述代码是可以等到 t1、t2、t3线程执行完毕了,如果 t 线程执行的任务里面出现了死循环,此时 main 线程不就无休止的等待了?确实如此,但是 join 给我们提供了一个带参数的方法,等指定的时间,到点就不等了! 如下代码:

public class Main {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{System.out.println("打开冰箱");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});Thread t2 = new Thread(()->{System.out.println("把大象装进去");try{Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}});Thread t3 = new Thread(()->{System.out.println("把冰箱关上");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}});t1.start();t1.join(10000);//main线程等待线程t1完成System.out.println("冰箱已经打开了");t2.start();t2.join(10000);//main线程等待线程t2完成System.out.println("大象已经装进去了");t3.start();t3.join(10000);//确保线程t3完成System.out.println("冰箱关上了,任务完成!");}
}

把大象装进冰箱的三个步骤,若是main线程等了10秒钟还没有完成该任务,那么main线程就不等了,10秒后冰箱门还不开就执行下一步了···· 

还有一种情况:

打开冰箱还需要10秒?t1说:我1秒就可以把冰箱打开了!然后 main 线程执行 t1.join() 的时候,但是 t1 线程的 run 方法已经执行完了,此时 join 就不会阻塞了,就会立即返回!

2.休眠当前线程

休眠线程其实我们前面已经用了,其本质就是让这个线程不参与调度了(不去 CPU 上执行)。

通过调用 Thread 类 中的 sleep 静态方法,传入指定时间,就能令线程休眠了。

注意:哪个线程里调用 Thread.sleep(1000),就让哪个线程休眠 1000 毫秒!

我们前面所说的 join 等待一个线程,当 main线程 调用到 t.join() 时候,main线程就要等待 t 线程 结束,此时main线程就进入了阻塞状态

而现在所讲的sleep休眠当前线程,也是进入阻塞状态!

那么如何进入阻塞状态呢? 

 在操作系统中有两个用于调度进程的重要队列:阻塞队列就绪队列, 当线程 t1 调用 sleep() 方法,就会进入阻塞队列,当 sleep 结束,就会进入就绪队列。

阻塞队列里的线程,也就是暂时不参与 CPU 的调度了,就绪队列中的线程,随时可以被 CPU 调度!

3.线程的所有状态

线程的状态是一个枚举类型Thread.State,我们可以打印出来看看都有哪些状态

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

  • NEW:                       安排了工作,还未开始行动,还没有调用 start 方法
  • RUNNABLE:           可工作的,又可以分成正在工作中即将开始工作
  • BLOCKED:             等待锁时产生的状态(锁竞争引起的阻塞)
  • WAITING:               调用 wait join 时进入的状态(死等引起的阻塞),
  • TIMED_WAITING:  调用 sleep 进入的状态
  • TERMINATED:       工作完成了

红标的状态都是阻塞状态,只是引起阻塞的原因不同,后面还会进行讲解

4.线程的状态转换 

线程从创建到销毁,期间会有一系列的状态变化,如下图: 

下面,我们通过代码来给大家演示一下线程的状态转换

public class Main {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 10_0000; i++) {}});System.out.println("start之前: " + t.getState());t.start();System.out.println("线程执行中的状态 : " + t.getState());Thread.sleep(1000);System.out.println("线程结束后的状态 : " + t.getState());}
}

当线程进入TERMINATED状态时,也就是线程结束后,线程所对应的PCB销毁了,这时就无法重新启动线程,重启就会抛出异常,但是线程所对应的对象t还没有被回收,我们仍然可以借助对象t来调用方法和属性,只是无法通过多线程来干活了!

接下来通过代码给大家演示一下线程 sleep 时候的 TIMED_WAITING 状态

public class Main {public static void main(String[] args) {final Object object = new Object();Thread t = new Thread(new Runnable() {@Overridepublic void run() {synchronized(object) {while(true) {try{Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}}}}});t.start();}

上述代码用到了 synchronized 这里暂时不作解释,将会在后续博客中进行讲解,我们可以看到,当我们的线程在循环执行 sleep ,此时我们就可以通过 jconsole 工具来查看线程的状态,该工具是jdk自带的,可以在bin目录中找到,有关于这个工具的讲解请看博主的上一篇博客 Thread类 的讲解,如上图所示,线程 sleep 后,就进入了TIMED_WAITING的状态,这个状态是线程在等待唤醒,等到一定时间没醒就自动醒了!

此时,我们可以修改一下上述的代码,把 t 中的 sleep 换成 wait ,我们来看看线程状态的变化

public class Main {public static void main(String[] args) {final Object object = new Object();Thread t = new Thread(new Runnable() {@Overridepublic void run() {synchronized(object) {while(true) {try{object.wait();
//                            Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}}}}});t.start();}

我们通过 jconsole工具看看此时线程的状态 

 如上图所示,我们可以看到此时线程的状态就是WAITNG状态了,WAITING状态是线程在无限等待唤醒,若是没有唤醒这个线程,那么这个线程就会一直等下去,也就是我们所说的“死等

 由于BLOCKED状态涉及到了锁竞争,这里暂时不作讲解,大家了解一下即可,这个状态是两个线程在争夺同一把锁引起的状态,在后续博客中还会进行讲解

感谢观看,希望对您有所帮助! 

下期预告:线程安全

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/690152.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ICode国际青少年编程竞赛- Python-4级训练场-嵌套for循环练习

ICode国际青少年编程竞赛- Python-4级训练场-嵌套for循环练习 1、 for i in range(3):Spaceship.step(4)for j in range(4):Dev.step(2)Dev.turnRight()Spaceship.turnLeft()Spaceship.step(4)Spaceship.turnRight()2、 for i in range(4):Spaceship.step(6)for j in range(3):…

JavaFX布局-HBox

JavaFX布局-HBox 常用属性alignmentspacingchildrenmarginpaddinghgrow 实现方式Java实现Xml实现 综合案例 HBox按照水平方向排列其子节点改变窗口大小,不会该部整体布局窗口太小会遮住内部元素&#xff0c;不会产生滚动条 常用属性 alignment 对齐方式 new HBox().setAlign…

Vue3:路由

1. 路由简介 在Vue3中&#xff0c;路由是一个核心概念&#xff0c;特别是在构建单页面应用程序&#xff08;SPA&#xff09;时。以下是Vue3中路由的基本概念&#xff1a; 1. **路由&#xff08;Route&#xff09;**&#xff1a;在Vue3中&#xff0c;路由是指根据特定的规则将用…

毕业论文凑字数——关于IVR自动语音应答交互式电话导航自动总机等等概念的一些剖析

目录 IVR毕业论文的讨巧思路IVR自动语音应答IVR的使用流程IVR的各种应用IVR的基本配置 一个小朋友的毕业论文要凑字数&#xff0c;所以推荐她讲一讲IVR&#xff0c;因为IVR可以翻译的名字很多&#xff0c;比如交互式语音应答&#xff0c;自动语音应答&#xff0c;自动语音服务&…

深度解析DPO及其变体在多种任务上的表现如何,该如何选择

深度学习自然语言处理 原创作者&#xff1a;wkk 单位&#xff1a;亚利桑那州立大学paper&#xff1a;Insights into Alignment:Evaluating DPO and its Variants Across Multiple TasksLink&#xff1a;https://arxiv.org/pdf/2404.14723 今天&#xff0c;我要带大家深入了解一…

高性能运营级流媒体服务框架:支持多协议互转 | 开源日报 No.250

ZLMediaKit/ZLMediaKit Stars: 12.6k License: NOASSERTION ZLMediaKit 是一个基于 C11 的高性能运营级流媒体服务框架。 使用 C11 开发&#xff0c;避免裸指针&#xff0c;代码稳定可靠&#xff0c;性能优越。支持多种协议 (RTSP/RTMP/HLS/HTTP-FLV/WebSocket-FLV/GB28181 等…

【软考高项】四十二、八大绩效域知识点

一、干系人绩效域 预期目标 建立高效的工作关系 检查&#xff1a;干系人参与的连续性 干系人认同项目目标 检查&#xff1a; 变更频率 支持项目的干系人提高了满意度&#xff0c;从中受益 检查&#xff1a;干系人行为、干系人满意度、干系人相…

使用xtuner微调InternLM-Chat-7B

1. 安装xtuner #激活环境 source activate test_llm # 安装xtuner pip install xtuner#还有一些依赖项需要安装 future>0.6.0 cython lxml>3.1.0 cssselect mmengine 2. 创建一个ft-oasst1 数据集的工作路径&#xff0c;进入 mkdir ft-oasst1 cd ft-oasst1 3.XTune…

2024最新从0部署Django项目(nginx+uwsgi+mysql)

云服务器 我这里用的是腾讯云免费试用的2H4Gcentos服务器&#xff08;后升级为2H8G&#xff0c;保险一点提高内存&#xff09; 因为网上很多关于django部属的教程都是宝塔啊&#xff0c;python版本控制器啊这种的&#xff0c;我也误打误撞安装了宝塔面板&#xff0c;但这里我…

JavaSE基础小知识Ⅱ(很容易错!!!)

1. 变量被final修饰后不能再指向其他对象&#xff0c;但可以重写 如果是引用变量被final修饰&#xff0c;那么的确如此&#xff1b; 基本变量不能重写 2. 下列代码的输出结果是&#xff1f; public class Test {static {int x 5; }static int x,y; public static void ma…

鸿蒙应用开发DevEco Studio工程目录模块介绍

面向开发者&#xff0c;HarmonyOS 推出了 DevEco Studio 和 Dev Device Tool 两款开发工具&#xff0c;前者目前迭代至 3.1 版本&#xff08;对外开放版本&#xff09;&#xff0c;用于开发 HarmonyOS 应用&#xff1b;后者用于开发智能设备 应用的工程主体结构如上图 在这里我…

JWT深入浅出

文章目录 JWT深入浅出1.JWT是什么2.为什么选JWT2.1 传统Session认证2.2 JWT认证 3.JWT怎么用4. jwt绝对安全吗&#xff1f; JWT深入浅出 1.JWT是什么 JWT&#xff08;JSON Web Token&#xff09;是一种用于在网络应用间传递信息的开放标准&#xff0c;通常用于身份认证和非敏…