【Java多线程(2)】Thread常见方法和线程状态

目录

一、Thread类及常见方法

1. join() 等待一个线程

2. currentThread() 获取当前线程引用

3. sleep() 休眠当前线程

二、线程的状态

1. 线程的所有状态

2. 状态转移


一、Thread类及常见方法

接上文:多线程(1)icon-default.png?t=N7T8http://t.csdnimg.cn/wuphT

Thread类中还有一些要介绍的方法 。

1. join() 等待一个线程

有时,我们需要等待⼀个线程完成它的工作后,才能进行下一步的工作。例如,张三只有等李四转账成功,才决定是否收钱,这时我们需要⼀个⽅法明确等待线程的结束。

public class Demo6 {public static void main(String[] args) throws InterruptedException {//join() 等待一个线程Thread t = new Thread(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("thread end");});t.start();//死等//t.join();    先打印 thread end  再打印 main end//最多等millis毫秒t.join(1000);System.out.println("main end");  //先打印 main end  再打印 thread end}
}

当在一个线程中调用另一个线程的 join() 方法时,当前线程会被阻塞,直到被调用的线程执行完成或超时。例如在上述代码中,调用 t.join() 表示 main 线程会等待 t 线程执行完成或超时,再执 行 main 线程。

  • 如果调用空参的 join() 方法,当前线程会一直被阻塞,直到被调用线程执行完成。
  • 如果调用有参的 join(long millis) 方法,当前线程会被阻塞指定的时间。如果指定时间内被调用线程执行完成,则结束阻塞状态,执行main线程;如果超出指定时间被调用线程没有执行完成,则main线程会继续执行,而被调用的线程仍然会继续执行直到完成。

因此,如果调用空参的 join() 方法,上述代码会先打印thread end,再打印 main end。如果调用有参的 join(long millis) 方法,由于main线程只等待1秒,而t线程会睡眠2秒,等待时间结束后t线程仍在睡眠,所以会先打印main end,再打印thread end。

2. currentThread() 获取当前线程引用

这个方法在前面就使用过了。

currentThread()Thread 类的静态方法,用于获取当前正在执行的线程对象。当调用 Thread.currentThread() 方法时,会返回表示当前线程的 Thread 对象。

使用场景:

  1. 在使用匿名内部类或者Lambda表达式中,由于还没有创建线程对象,我们就可以用currentThread()方法获取当前线程引用。
  2. 创建线程的第二种方式中,由于 Runnable 接口本身并不包含与线程相关的方法,而只有一个 run() 方法。因此,在实现 Runnable 接口时,需要将其实现类传递给 Thread 对象的构造函数,然后通过 Thread 对象来创建和管理线程。所以就可以通过 Thread.currentThread() 方法来获取当前线程的引用。

而用创建线程的第一种方式中,我们是通过继承Thread类创建线程,就可以直接用this获取当前线程的引用了。

public class Demo7 {public static void main(String[] args) {//currentThread() 获取当前线程引用Thread thread = Thread.currentThread();System.out.println(thread.getName());}
}

3. sleep() 休眠当前线程

这也是我们前面就一直在使用的方法。

sleep() 方法是 Thread 类的一个静态方法,它让当前线程暂停执行指定的时间。在调用 sleep() 方法后,当前线程会暂时放弃 CPU 的执行权,进入阻塞状态,让其他线程有机会执行。一旦休眠时间结束,线程就会重新进入就绪状态,等待CPU调度执行。

注意事项:

  • 在理论上,调用 Thread.sleep() 方法后,线程会暂停执行指定的时间,但实际休眠时间可能会略微超过设置的休眠时间。这是由于操作系统调度和线程切换所带来的额外开销和延迟。
  • 具体来说,Thread.sleep() 方法是通过将当前线程置于休眠状态来实现延迟,但并不保证在精确的时间后唤醒线程。操作系统和 JVM 在处理线程睡眠时可能会引入一些额外的延迟,比如线程调度、上下文切换等。因此,实际休眠时间可能会略微超过设置的休眠时间,但通常不会有太大的偏差。

也就是说,当休眠时间到了之后,线程从阻塞状态恢复到运行状态,但不代表线程就能立即去CPU上执行。

public class Demo8 {public static void main(String[] args) throws InterruptedException {long prevTime = System.currentTimeMillis();Thread.sleep(1000);long currTime = System.currentTimeMillis();System.out.println("实际休眠时间:" + (currTime - prevTime));}
}

在这段代码中,首先记录了调用 Thread.sleep(1000) 前的时间戳 prevTime,然后让当前线程休眠1秒钟(1000毫秒),接着再获取休眠后的时间戳 currTime,最后计算并输出两个时间戳之间的差值,即实际休眠时间。

二、线程的状态

1. 线程的所有状态

线程的状态是⼀个枚举类型 Thread.State

 而 RUNNABLE 状态又可以分成两种状态:1.正在工作中(RUNNING),2.即将开始工作(READY)。

2. 状态转移

  1. 新建 -> 就绪:当调用线程的 start() 方法启动线程时,线程从新建状态转移到就绪状态。
  2. 就绪 -> 运行:当线程获取到 CPU 时间片开始执行时,线程从就绪状态转移到运行状态。
  3. 运行 -> 阻塞:当线程需要等待某个条件满足时,如调用 sleep() 方法或者等待 I/O 操作完成时,线程从运行状态转移到阻塞状态。
  4. 运行 -> 终止:线程执行完任务或者出现异常导致线程结束时,线程从运行状态转移到终止状态。
  5. 阻塞 -> 就绪:当线程等待的条件满足或者资源释放后,线程从阻塞状态转移到就绪状态。
  6. 就绪 -> 终止:线程执行完任务或者出现异常导致线程结束时,线程从就绪状态转移到终止状态。
通过一个示例来看NEW、RUNNABLE和TERMINATED状态的转换:
public class Demo9 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}});//NEW: 安排了⼯作, 还未开始⾏动System.out.println(t.getState());t.start();//RUNNABLE: 可⼯作的. ⼜可以分成正在⼯作中(RUNNING)和即将开始⼯作(READY).System.out.println(t.getState());t.join(); //让main线程等待t线程执行完毕//TERMINATED: ⼯作完成了.System.out.println(t.getState());}
}

1. 已经创建了线程对象,但还未开启线程,处于NEW状态。

2. 开启线程,线程处于执行中,是RUNNABLE状态。

3. t线程执行完成,为TERMINATED状态。

最后看下另外的三种状态(需要使用 jconsole 工具和后续内容锁): 

  1. 阻塞(Blocked):线程被挂起,等待某个条件满足或者等待其他资源释放。比如调用 sleep()wait() 方法或者等待 I/O 操作完成时会进入阻塞状态。
  2. 等待(Waiting):线程进入等待状态,等待其他线程通知唤醒。比如调用 Object.wait()Thread.join() 或者 LockSupport.park() 方法时会进入等待状态。
  3. 超时等待(Timed Waiting):与等待状态类似,不同之处在于可以设置一个超时时间,在超时时间到达前等待或者在接收到通知前等待。比如调用 Thread.sleep()Object.wait(timeout) 或者 Thread.join(timeout) 方法。

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

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

相关文章

git-怎样把连续的多个commit合并成一个?

Git怎样把连续的多个commit合并成一个? Git怎样把连续的多个commit合并成一个? 参考URL: https://www.jianshu.com/p/5b4054b5b29e 查看git日志 git log --graph比如下图的commit 历史,想要把bai “Second change” 和 “Third change” 这…

【Linux系统zabbix安装部署】

1、安装lamp环境 [rootlocalhost software]# yum -y install mariadb mariadb-server httpd php php-mysql [rootlocalhost software]# systemctl enable httpd [rootlocalhost software]# systemctl restart htpd [rootlocalhost software]# systemctl restart httpd [rootloc…

cinder学习小结

1 官方文档 翻译官方文档学习 链接Cinder Administration — cinder 22.1.0.dev97 documentation (openstack.org) 1.1 镜像压缩加速 在cinder.conf配allow_compression_on_image_upload True可打开开关 compression_format xxx可设置镜像压缩格式,可为gzip 1.2 …

手撕算法-数组中的第K个最大元素

描述 分析 使用小根堆&#xff0c;堆元素控制在k个&#xff0c;遍历数组构建堆&#xff0c;最后堆顶就是第K个最大的元素。 代码 class Solution {public int findKthLargest(int[] nums, int k) {// 小根堆PriorityQueue<Integer> queue new PriorityQueue<>…

【python从入门到精通】-- 第二战:注释和有关量的解释

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

鸿蒙 HarmonyOS应用开发之API:Context

Context 是应用中对象的上下文&#xff0c;其提供了应用的一些基础信息&#xff0c;例如resourceManager&#xff08;资源管理&#xff09;、applicationInfo&#xff08;当前应用信息&#xff09;、dir&#xff08;应用文件路径&#xff09;、area&#xff08;文件分区&#x…

mybatis 实验报告1

文章目录 新建数据库新建项目&#xff0c;并导入jar包添加配置文件conf.xml定义实体类定义操作表user的sql的映射文件 userMapper.xml注册&#xff1a;将mapper.xml文件注册到conf.xml配置文件中一共6步&#xff0c;这个只是测试类&#xff0c;这个不算 新建数据库 命名是 随便…

嵌入式学习笔记(四)

LoadStore内存读写指令 单寄存器读写指令 指令码 ----------------ldr : 从内存地址中读取数据到寄存器中&#xff0c;读4个字节的数据str : 将寄存器中的数据写到内存地址中&#xff0c;写4个字节的数据 ------------------------------------------------------ldrh : 从内…

nandgame中的控制单元(Control Unit)

关卡说明的翻译&#xff1a; 控制单元除了ALU指令之外&#xff0c;计算机还应支持数据指令。在数据指令中&#xff0c;指令值直接写入A寄存器。创建一个控制单元&#xff0c;根据指令I的高位执行数据指令或ALU指令&#xff1a;位 15 0 数据指令 1 ALU指令ALU指令 对于ALU指令&…

Grok-1开源革新:探索人工智能的新境界

Grok-1开源革新&#xff1a;探索人工智能的新境界 在科技发展的马拉松中&#xff0c;Elon Musk旗下的xAI公司稳步前进&#xff0c;推出了名为Grok-1的语言模型。这个巨型模型&#xff0c;作为目前参数量最大的开源人工智能语言模型&#xff0c;赋予了机器学习领域全新的活力。 …

C#学习笔记4:PC串口发送数据

今日继续我的C#学习之路&#xff0c;今日学习制作PC串口发送数据的窗口程序 串口是单片机上位机开发的重点&#xff0c;本文围绕做一个通过PC端串口发送数据的程序进行实践学习&#xff0c; 文章提供源码与解释、整体工程文件 目录 1、控件的选择与摆放&#xff1a; 2、程序设…

435. 无重叠区间(力扣LeetCode)

文章目录 435. 无重叠区间题目描述贪心算法解题思路&#xff1a; 435. 无重叠区间 题目描述 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 示例 1: 输入: intervals [[1,…

2024.3.26

实现闹钟 weiget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTimer> #include<QTime> #include<QTimerEvent> #include<QString> #include<QtTextToSpeech> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } Q…

计算机复试面试问答准备(未完)

目录 1、理解多态性2、怎么逆置⼀个链表3、顺序表和链表的区别4、树的存储结构5、什么是哈夫曼树&#xff1f;简述哈夫曼树的构造过程。介绍哈夫曼树的特性。6、哈夫曼编码的编码和解码过程7、图的遍历方式8、图的存储方式9、最小生成树10、迪杰斯特拉算法11、佛洛依德算法12、…

mysql刨根问底

索引&#xff1a;排好序的数据结构 二叉树&#xff1a; 红黑树 hash表&#xff1a; b-tree&#xff1a; 叶子相同深度&#xff0c;叶节点指针空&#xff0c;索引元素不重复&#xff0c;从左到右递增排序 节点带data btree&#xff1a; 非叶子节点只存储索引&#xff0c;可…

C语言经典例题(8) --- 进制A+B、网购、及格分数、最高分数、计算一元二次方程

文章目录 1.进制AB2.网购3.及格分数4.最高分数5.计算一元二次方程 1.进制AB 题目描述&#xff1a; 输入一个十六进制数a&#xff0c;和一个八进制数b&#xff0c;输出ab的十进制结果&#xff08;范围-231~231-1&#xff09;。 输入描述&#xff1a; 一行&#xff0c;一个十六…

不使用额外空间交换两个数

1) 算术x x y;y x - y;x x - y; 2) 异或x x^y;// 只能对int,char..y x^y;x x^y;x ^ y ^ x;加法和异或这两种方法都是用于交换两个数的值而不使用额外空间的方法。它们的适用类型如下&#xff1a; 加法方法&#xff1a; 适用于整数类型&#xff08;int、long、long lo…

C++对象的创建和使用

定义了类&#xff0c;就相当于定义了一个数据类型。类与int、char等数据类型的使用方法是一样的。可以定义变量&#xff0c;数组和指针等。使用类定义的变量通常称为该类的对象。 对象的定义格式如下&#xff1a; 类名 对象名; 1.对象访问其成员 对象通过"."访问它的…

[NCNN学习笔记]-4

1、前言 继续学习NCNN。本次学习binaryop和eltwise。 2、学习内容 2.1、binaryop binaryop是用来二元计算的op&#xff0c;先来看binaryop.h的中关于二元计算的定义&#xff0c;其中二元计算定义了如下操作。 enum OperationType {Operation_ADD 0,Operation_SUB 1,Oper…

垃圾回收:垃圾回收器

目录 垃圾回收器 评估GC的性能指标 7种典型的垃圾回收器 Serial回收器&#xff1a;串行回收 ParNew回收器&#xff1a;并行回收 Parallel回收器&#xff1a;吞吐量优先 CMS回收器&#xff1a;低延迟 G1回收器&#xff1a;区域化分代式 G1回收过程1-年轻代GC G1回收过程…