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://xiahunao.cn/news/2906370.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习概论—增强学习

机器学习概论—增强学习 强化学习(Reinforcement Learning, RL)或者说是增强学习,是机器学习的一个领域,旨在使智能体通过与环境的交互学习如何做出决策,它是关于在特定情况下采取适当的行动来最大化奖励。它被各种软件和机器用来寻找在特定情况下应采取的最佳行为或路径…

在.Net6中用gdal实现第一个功能

目录 一、创建.NET6的控制台应用程序 二、加载Gdal插件 三、编写程序 一、创建.NET6的控制台应用程序 二、加载Gdal插件 Gdal的资源可以经过NuGet包引入。右键单击项目名称&#xff0c;然后选择 "Manage NuGet Packages"&#xff08;管理 NuGet 包&#xff09;。N…

视频素材免费哪个好?7个视频素材下载网站推荐

小伙帮们准备做视频的时候才发现&#xff0c;哎呀&#xff0c;高清视频素材哪里找啊&#xff1f;不用急&#xff0c;这次我们依旧从中国的宝藏网站开始&#xff0c;然后穿越全球&#xff0c;发现更多精彩的无水印视频素材网站 1&#xff0c;蛙学府&#xff08;中国&#xff09…

辅助驾驶-ACC

自适应巡航&#xff08;ACC&#xff09;使汽车能够自动调整自身速度与前车保持安全的行驶距离。 从整车系统层面考虑&#xff0c; ACC 是一个多种控制单元联合参与才能实现的功能。在这个系统中&#xff0c;雷达或者摄像头除了作为传感器提供目标车信息&#xff0c;核心的 ACC …

Postman中参数填写方式!

Postman中参数填写和请求方法有关&#xff0c;一般接口用例请求方法GET与POST常用&#xff0c;所以主要是这两种请求方法请求参数填写 一、GET请求方法参数填写 1、直接在URL中填写请求参数,如直接在URL中填写&#xff1a; http://www.example.com:8089/userapi?unamelisi&…

蓝桥杯练习题 近似GCD 双指针

题目 小蓝有一个长度为 n 的数组 4 (a1, a2,,an),数组的了数组被定义为从 原数组中选出连续的一个或多个元素组成的数组。数组的最大公约数指的是数 组中所有元素的最大公约数。 如果最多更改数组中的一个元素之后,数组的最大公约数为 g,那么称 g 为这个数组的近似GCD。 一个数…

大数据做「AI大模型」数据清洗调优基础篇

关于本文 近期一直在协助做AI大模型数据清洗调优的工作&#xff0c;主要就是使用大数据计算引擎Spark做一些原始数据的清洗工作&#xff0c;整体数据量大约6PB-8PB之间&#xff0c;那么对于整个大数据量的处理性能将是一个重大的挑战&#xff0c;关于具体的调优参数配置项暂时不…

13-API风格(下):RPCAPI介绍

RPC在Go项目开发中用得也非常多&#xff0c;需要我们认真掌握。 RPC介绍 根据维基百科的定义&#xff0c;RPC&#xff08;Remote Procedure Call&#xff09;&#xff0c;即远程过程调用&#xff0c;是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机…

1.5-数组-059. 螺旋矩阵 II★★

59. 螺旋矩阵II ★★ 力扣题目链接&#xff0c;给你一个正整数 n &#xff0c;生成一个包含 1 到 n 2 n^2 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。1 < n < 20 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,…

mp4转rmvb怎么转?超快的方法分享!

RMVB&#xff08;RealMediaVariableBitrate&#xff09;是由RealNetworks公司推出的一种视频文件格式。相较于其他视频格式&#xff0c;RMVB以其高度压缩和可变比特率的特性而著称。它常被用于网络视频传输&#xff0c;适用于带宽有限或网络环境较差的情况。 RMVB文件格式的特性…

arp 协议

数据链路层 我们之前学习到的 IP 协议解决的是数据跨网络传输的问题。 数据链路层解决的是&#xff1a;直接相连的主机&#xff0c;进行数据交付的问题&#xff01; 直接相连的设备包括我们的电脑&#xff0c;路由器等等哈&#xff01; 我们在网络基础那篇文章中讲过什么是以…

音频怎么转换成二维码?1分钟在线生成音频二维码

音频是现在很常见一种内容展现方式&#xff0c;很多人会通过音频文件来做推广传播&#xff0c;在很多的应用场景中&#xff0c;音频用来为用户提供内容&#xff0c;从而提升用户体验效果。 为了方便用户能够快速的获取音频文件&#xff0c;通过将音频生成二维码之后&#xff0…

基于单片机的便携式瓦斯检测仪系统设计

**单片机设计介绍&#xff0c;基于单片机的便携式瓦斯检测仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的便携式瓦斯检测仪系统设计是一个针对煤矿等工业环境中瓦斯气体浓度检测的重要项目。以下是该设计…

【单调栈】力扣84.柱状图中最大的矩形

上篇文章我们介绍了使用 无重复值 单调栈代码解决 含有重复值 的问题&#xff0c;在文章的最后&#xff0c;留下了一道考察相同思想的题目&#xff0c;今天我们来看看如何套路解决该题。 &#xff08;还没看过前几篇介绍的小伙伴赶快关注&#xff0c;在 「单调栈」 集合里查看…

启信宝商业大数据助力全国经济普查

近日&#xff0c;合合信息旗下启信宝收到中国青年创业就业基金会感谢信&#xff0c;对启信宝协同助力全国经济普查和服务青年创业就业研究表达感谢。 第五次全国经济普查是新时代新征程上一次重大国情国力调查&#xff0c;是对国民经济“全面体检”和“集中盘点”&#xff0c;…

2024年最受欢迎的视频号小店,怎么做才能月入过万?两步教会你

大家好&#xff0c;我是电商花花。 要说现在最火的项目&#xff0c;我觉得是视频号小店&#xff0c;现在视频号小店经过两年时间的沉淀&#xff0c;让更多人看到了视频号强大私域转化和高利润空间。 抖音小店我们应该也都知道&#xff0c;现在现在的抖音小店利润是不是变小了…

ESCTF-密码赛题WP

*小学生的爱情* Base64解码获得flag *中学生的爱情* 社会主义核心价值观在线解码得到flag http://www.atoolbox.net/Tool.php?Id850 *高中生的爱情* U2FsdG开头为rabbit密码,又提示你密钥为love。本地toolfx密码工具箱解密。不知道为什么在线解密不行。 *大学生的爱情* …

lua脚本在redis集群中哈希槽分片问题

上文说到&#xff0c;通过用redis lua脚本实现时间窗分布式限流 可以操作redis lua脚本来实现时间窗限流&#xff0c;在执行lua脚本的时候&#xff0c;参数中有个keys列表&#xff0c;当lua脚本中如果有操作多个key的情况&#xff0c;就可以传个key列表了。通常情况下&#xff…

java 抠取红色印章(透明背景)

一个亲戚让我帮他把照片里的红色印章抠出来&#xff0c;&#xff0c;&#xff0c;记录下处理过程&#xff0c;代码如下&#xff0c;可直接用&#xff1a; public static void signatureProcess(String sourceImagePath, String targetImagePath) {Graphics2D graphics2D null…

Nginx_简介 + Linux系统下详细安装教程指路

安装教程指路 可参看该视频【尚硅谷Nginx教程&#xff08;亿级流量nginx架构设计&#xff09;】 https://www.bilibili.com/video/BV1yS4y1N76R/?p2&share_sourcecopy_web&vd_source4c2f33f3ba1a0dd45bfdf574befd0069 的p2-p7。从安装centos虚拟机到在虚拟机上安装ng…