JavaEE 初阶篇-深入了解多线程等待与多线程状态

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 线程等待

        1.1 线程等待 - join() 方法

        1.1.1 main 线程中等待多个线程

        1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程

        1.1.3 其他线程阻塞等待 main 线程

        1.1.4 在指定的时间内阻塞等待

        1.2 线程等待 - Thread.sleep() 方法

        2.0 线程状态

        2.1 新建状态 - NEW

        2.2 就绪状态 - Runnable

        2.3 终止状态 -Terminated

        2.4 等待状态 - Waiting

        2.5 超时等待状态 - Time_Waiting

        2.6 阻塞状态 - Blocked

        2.7 线程状态之间的相互转换图


        1.0 线程等待

        在线程编程中,线程等待是指一个线程暂停执行,直到某个条件满足或者其他线程执行完毕后再继续执行。线程等待的方法:join() 方法Thread.sleep() 方法等等

        1.1 线程等待 - join() 方法

       join() 方法是 Thread 类的一个方法,用于让一个线程等待另一个线程执行完毕。当在一个线程对象上调用 join() 方法时,当前线程会被阻塞,直到被调用的线程执行完毕。

        具体来说,调用 thread.join() 会使当前线程等待 thread 线程执行完毕。如果 thread 线程已经执行完毕,那么 join() 方法会立即返回;如果 thread 线程还在执行,当前线程会被阻塞,直到 thread 线程执行完毕。

代码如下:

public class demo1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 1000; i++) {System.out.println("正在执行 thread 线程");}});thread.start();thread.join();System.out.println("执行 main 线程");}
}

        main 线程调用 thread.join() ,就会阻塞 main 线程继续执行,会让 thread 线程执行完毕之后,main 线程解除阻塞,继续执行下去。

运行结果:

补充: main 中调用 join() 方法,有以下可能性:

        1.0 如果 t 线程此时已经结束了,此时 join() 方法就会立即返回。

        2.0 如果 t 线程此时还没有结束,此时 main 就会阻塞等待,一直等待到 t 线程结束之后,main 线程才会接触阻塞,继续执行。

        3.0 如果调用等待阻塞的线程对象还没创建 pcb 的时候(即还没 start() 的时候),那么调用 join() 方法的线程会直接解除阻塞。

        1.1.1 main 线程中等待多个线程

        在 main 线程中多次调用 join() 方法时,先执行 t1.join(),如果 t1 还没结束,main 继续阻塞等待,t1 结束之后,继续执行 t2.join() 方法,再等待 t2 结束。注意,t1 与 t2 之间同样是抢占式执行随机调度,所以先后顺序对于 main 线程来说没有什么区别。

代码如下:

public class demo2 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 t1 线程");}});Thread t2 = new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 t2 线程");}});t1.start();t2.start();t1.join();t2.join();System.out.println("正在执行 main 线程");}
}

运行结果:

        1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程

        这种情况是按顺序执行的,大致就是串行执行一样。顺序为:先要执行完 t1 再执行 t2 最后再执行 main 线程。

代码如下:

public class demo3 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 t1 线程");}});Thread t2 = new Thread(()->{try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 t2 线程");}});t1.start();t2.start();t2.join();System.out.println("执行 main 线程");}
}

        t1.start() 立即创建 t1 线程,再 t2.start() 创建线程,t1 没有任何阻塞就会直接执行代码,而 t2 遇到了阻塞,需要等待 t1 执行完毕之后,t2 才会解除阻塞,同时由于 main 线程阻塞了,需要等待 t2 执行完毕,当 t2 执行完毕之后,main 线程解除阻塞了,执行 main 线程中的代码。

运行结果:

        1.1.3 其他线程阻塞等待 main 线程

        t1 线程阻塞等待 main 线程执行完毕之后,再执行 t1 线程。

代码如下:

public class demo4 {public static void main(String[] args) throws InterruptedException {//拿到当前 main 线程对象Thread mainThread = Thread.currentThread();Thread t1 = new Thread(()->{//在 t1 线程中调用 join() 方法,//阻塞当前 t1 线程,等待 main 线程执行完毕try {mainThread.join();} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 t1 线程");}});t1.start();for (int i = 0; i < 5; i++) {Thread.sleep(1000);System.out.println("正在执行 main 线程");}}
}

运行结果:

        1.1.4 在指定的时间内阻塞等待

        join() 方法还有一个重载的版本,可以指定一个超时时间,即 join(long millis),表示当前线程最多等待 millis 毫秒,如果超过这个时间 thread 线程还没有执行完毕,当前线程会继续往下执行。简单来说,即使 thread 这个线程还没有结束,main 线程都不会继续等待了;如果 thread 在规定的时间内提前结束,那么 main 也会提前解除阻塞。

代码如下:

public class demo5 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 1000; i++) {System.out.println("正在执行 thread 线程");}});thread.start();//等待 0.1 s 就解除阻塞 main 线程,即不会继续等待了thread.join(1000);System.out.println("正在执行 main");}
}

运行结果:

        1.2 线程等待 - Thread.sleep() 方法

        是一个静态方法,它使当前线程暂停执行一段时间。该方法接受一个以毫秒为单位的时间参数,指定线程暂停的时间长度。在这段时间内,线程不会执行任何操作,但是线程的状态仍然是 Runnable 状态,可以随时被调度器调度执行。

        需要注意的是,Thread.sleep() 方法不是真正意义上的线程等待,它只是让线程暂停执行一段时间,不会释放锁或资源。在实际开发中,应根据具体需求选择合适的线程等待机制,以确保程序的正确性和效率。

代码如下:

public class demo6 {public static void main(String[] args) {Thread thread = new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 thread 线程");}});thread.start();}
}

运行结果:

        每相隔 1 秒就会输出一次。

        需要注意的是,这里的 Thread.sleep() 方法是受查异常,且 run() 是重写父类的方法,该 run() 方法的方法名、参数列表、声明异常都需要与父类保持一致,因此这里不能声明异常,只能捕获异常处理。

        2.0 线程状态

        在 Java 中主要包括六种不同的状态。

        2.1 新建状态 - NEW

        当创建一个线程对象时,线程处于新建状态,此时线程对象已经创建好了,但是还没调用 start() 方法启动线程,因此线程还没被创建出来

        2.2 就绪状态 - Runnable

        有两种情况都属于就绪状态:1)还没运行,就绪状态。但是线程已经准备好运行了,只等待被 CPU 调度执行。2)线程正在被 CPU 调度执行中,运行状态。总而言之,无论是就绪状态还是运行状态在 Java 中都属于 Runnable 状态,即就绪状态。

        2.3 终止状态 -Terminated

        线程执行完任务后或者出现异常导致线程终止时,线程进入终止状态。在终止状态下,线程不再执行任务。

        2.4 等待状态 - Waiting

        线程进入等待状态通常时因为调用了 thread.join() 方法等等。

代码如下:

public class demo7 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (true){System.out.println(1);}});thread.start();thread.join();System.out.println("正在执行 main 线程");}
}

演示线程等待:

        main 线程调用了 thread.join() 方法阻塞等待 thread 线程,又因为 thread 还当前为止还没结束, 所以当前 main 线程被阻塞了,因此 main 状态为 Waiting 状态。对于 thread 线程来说,目前的状态为 Runnable 状态。

        2.5 超时等待状态 - Time_Waiting

        线程调用带有超时参数的等待方法,比如 Thread.sleep(long millis) 等待方法。线程会进入超时等待状态下,线程会等待一段时间后自动恢复到就绪状态。

代码如下:

public class demo8 {public static void main(String[] args) {Thread thread = new Thread(()->{try {Thread.sleep(9000000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("正在执行 thread 线程");});thread.start();System.out.println("正在执行 main 线程");}
}

演示超时等待:

        2.6 阻塞状态 - Blocked

        线程在特定情况下,会进入阻塞状态,比如调用了 Thread.sleep() 方法或者加锁。在线程阻塞状态下,线程暂时停止执行,直到满足特定条件后,才能继续执行。

代码如下:

死锁状态:两个线程两把锁

public class demo10 {public static void main(String[] args) {Object o1 = new Object();Object o2 = new Object();Thread t1 = new Thread(()->{synchronized (o1){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (o2){System.out.println("正在执行 t1 线程");}}});Thread t2 = new Thread(()->{synchronized (o2){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (o1){System.out.println("正在执行 t2 线程");}}});t1.start();t2.start();}
}

演示阻塞状态:

        2.7 线程状态之间的相互转换图

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

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

相关文章

期货开户要找到适合自己的系统

物有一个生物圈&#xff0c;大鱼吃小鱼&#xff0c;小鱼吃虾。在期货市场这条生物圈里面&#xff0c;大部分人就是期货市场的虾子&#xff0c;是被吃的&#xff0c;所以必须成长起来&#xff0c;往更高一层走&#xff0c;到可以吃虾子的时候&#xff0c;就是挣钱的时候。学习不…

物流监控升级,百递云·API开放平台助力某电商平台实现高效物流管理

不论是电商平台自身还是消费者&#xff0c;都有着对物流监控的强烈需求。 消费者下单后be like: 每十分钟看一次快递轨迹 放心&#xff0c;电商平台也一样关心物流状态&#xff01;怎样第一时间向用户传递物流状态&#xff1f; 怎么减少重复的提问和投诉&#xff1f;怎样监管…

2023年EI会议论文已见刊/检索进展汇总

2023年录用的会议论文已在SPIE、ACM、IEEE等出版社正式上线见刊&#xff0c;并已陆续完成EI Compendex数据库收录&#xff0c;详情如下&#xff1a; EIECT 2023——IEEE出版&#xff0c;并完成EI收录 会议信息&#xff1a; 第三届电子信息工程与计算机技术国际学术会议&…

cesium vue 绘制标记实体(撒点),监听鼠标左击事件

添加实体 const viewer new Cesium.Viewer(cesiumContainer, {})viewer.entities.add()查看实体 const viewer new Cesium.Viewer(cesiumContainer, {}) const billboard viewer.entities.add({...})viewer.zoomTo(billboard)删除实体 根据实体删除 if (billboard.value…

治愈自己的短句,心灵鸡汤!

一、不是所有的是非都能理清&#xff0c;不是所有的付出都有收获。有些选择是无可奈何&#xff0c;有些失去是注定的。与其无法言说&#xff0c;不如一笑而过&#xff1b;与其无法释怀&#xff0c;不如安然自若。 二、没人会真正的感同身受到你的痛楚&#xff0c;也没人会真正…

server端

一、创建项目 expess server 1.1 安装nodemon npm i nodemon 1.2 设置连接数据库mongodb 安装mongoose npm i mongoose 在根目录新建config文件夹/db.config.js // 引入mongodb数据库操作模块 const mongoose require("mongoose") // 连接数据库mongoose.con…

【面试那些事儿】浏览器键入网址到网页显示,期间发生了什么

当用户在浏览器中键入网址并按下回车键后&#xff0c;直到最终显示出完整的网页内容&#xff0c;这一过程中经历了哪些步骤呢&#xff1f; 这是一道经典的面试题&#xff0c;我们来看看具体有哪些阶段。 1. 解析URL 浏览器首先解析用户输入的URL&#xff0c;判断它的语法和协…

FastText 增量训练

1.安装正确版本 &#xff08;1&#xff09;下载IncrementalTraining分支代码GitHub - SergeiAlonichau/fastText at IncrementalTraining&#xff0c;或者下载资源&#xff1b; &#xff08;2&#xff09;将上一步下载的zip进行解压&#xff0c;然后进入文件夹执行make操作即…

Linux 动静态库的制作,使用和加载

Linux 动静态库的制作,使用和加载 一.前置说明1.mylib.h2.mylib.c3.mymath.h mymath.c4.如何制作库 二.动静态库的制作1.静态库的制作1.制作2.使用一下静态库,验证是否成功打包 2.动态库的制作1.编译.c源文件文件生成.o目标文件2.打包生成动态库3.编写makefile文件,自动化制作动…

【问题分析】InputDispatcher无焦点窗口ANR问题【Android 14】

1 问题描述 Monkey跑出的无焦点窗口的ANR问题。 特点&#xff1a; 1&#xff09;、上层WMS有焦点窗口&#xff0c;为Launcher。 2&#xff09;、native层InputDispacher无焦点窗口&#xff0c;上层为”recents_animation_input_consumer“请求了焦点&#xff0c;但是”rece…

Abaqus2024混凝土随机多边形及界面层插件AbyssFish_RandomPolygon2D V2版本更新

很高兴地向大家宣布&#xff0c; AbyssFish_RandomPolygon2D插件已经迎来了重要更新&#xff01;本次更新旨在适配Python3版本的Abaqus2024&#xff0c;并优化插件界面&#xff0c;提升用户体验。同时我们为所有已购买旧版本插件的用户提供免费升级服务&#xff01; 插件介绍…

ESP32

MicroPython 是运行在微控制器硬件之上的完全的Python编译器和运行时系统。提供给用户一个交互式提示符(REPL)来立即执行所支持的命令。 你们那么 。 交互式提示符&#xff08;REPL&#xff09;是MicroPython提供给用户的一种界面&#xff0c;它允许用户在…