多线程中Thread的join方法

join简介

join方法Thread类中的一个方法,该方法的定义是等待该线程执行直到终止。其实就说join方法将挂起调用线程的执行,直到被调用的对象完成它的执行。

join实例(以一道面试题为例)

现在有T1、T2、T3三个线程,你怎样保证T2T1执行完之后执行,T3T2执行完后执行?这个问题是网上很热门的面试题(这里除了join还有很多方法能够实现,只是使用join是最简单的方案),下面是实现的代码:

/*** @author wcc* @date 2021/8/21 20:46* 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?*/
public class JoinDemo {public static void main(String[] args) {//初始化线程1,由于后续有匿名内部类调用这个局部变量,需要用final修饰//这里不用final修饰也不会报错的原因 是因为jdk1.8对其进行了优化/*在局部变量没有重新赋值的情况下,它默认局部变量为final类型,认为你只是忘记了加final声明了而已。如果你重新给局部变量改变了值或者引用,那就无法默认为final了*/Thread t1=new Thread(new Runnable() {@Overridepublic void run() {System.out.println("t1 is running...");}});//初始化线程二Thread t2=new Thread(new Runnable() {@Overridepublic void run() {try {t1.join();} catch (InterruptedException e) {e.printStackTrace();}finally {System.out.println("t2 is running...");}}});//初始化线程三Thread t3=new Thread(new Runnable() {@Overridepublic void run() {try {t2.join();} catch (InterruptedException e) {e.printStackTrace();}finally {System.out.println("t3 is running...");}}});t1.start();t2.start();t3.start();}}

输出结果:

t1 is running...
t2 is running...
t3 is running...

结果分析:

t2线程中t2本身就是调用线程,所谓的调用线程是指调用了t.join()方法的线程,而被调用的对象指的是调用join方法的线程对象,即t1。所以这三个线程按照t1 -> t2 -> t3的顺序执行了。

join方法源码解析

 /*** 等待该线程终止的时间最长为millis毫秒,超时时间为0意味着要一直等下去* @param millis 以毫秒为单位的等待时间* @throws InterruptedException*/public final synchronized void join(long millis)throws InterruptedException {//获取启动的时间戳,用于计算当前时间long base = System.currentTimeMillis();//当前时间long now = 0;if (millis < 0) { //等待时间不能小于0 否则抛出IllegalArgumentException异常终止程序throw new IllegalArgumentException("timeout value is negative");}//判断是否携带阻塞的超时时间,等于0则表示没有设置超时时间//如果超时时间为0 则意味着一直要等待该线程执行完(无限等待)if (millis == 0) {//需要注意的是,如果当前线程未被启动或者已经终止,则isAlive方法返回false//即意味着join方法不会生效while (isAlive()) {//isAlive()方法:判断当前线程是否处于活动状态//活动状态就是线程已经启动并且尚未终止wait(0);}} else { //设置了超时时间//需要注意的是,如果当前线程未被启动或者已经终止,则isAlive方法返回false//即意味着join方法不会生效while (isAlive()) {,//计算剩余时间long delay = millis - now;if (delay <= 0) { //如果剩余等待的时间小于等于0,则终止等待break;}//等待指定时间wait(delay);//获取此次循环执行的时间now = System.currentTimeMillis() - base;}}}

从源码中可以得知,如果想要join方法正常生效,调用join方法的线程对象必须已经调用了start()方法并且未进入终止状态。

扩展:

从join方法的源码来看,join方法的本质调用的是Object中的wait方法实现线程的阻塞,wait方法的实现原理在后续的文章中在说详细阐述。**但是我们需要知道的是,调用wait方法必须要获取锁,**所以join方法是被synchronized修饰的,synchronized修饰在很多层面相当于synchronized(this),this就说Thread本身的实例。

有很多人不理解join为什么阻塞的是主线程呢?不理解的原因是阻塞主线程的方法是放在Thread这个实例中的作用,让大家误以为应该阻塞thread线程。实际上主线程会持有thread这个对象的锁,然后调用wait方法去阻塞,而这个方法的调用者是在主线程中的。所以造成主线程阻塞。

第二个问题:为什么Thread线程执行完毕就能够唤醒主线程呢?或者说在什么时候唤醒的呢?

要了解这个问题,我们又得翻jdk源码,但是如果对线程有既定得基本了解得话,通过wait方法阻塞得线程,需要通过notify或者notifyAll()方法来唤醒。所以在线程执行完毕以后会有一个唤醒得操作,只是在虚拟机内部通过调用native方法实现得

多线程中Thread的join方法相关推荐

  1. 多线程--关于Thread的join方法

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.Thread的join方法. 二.方便理解引入例子 1.代码示例 2.输出结果 总结 一.Thread的join方法. ...

  2. java thread join_java中thread的join方法为什么能让线程插队

    在面试中经常会遇到这样的问题:在主线程中有两个子线程,如果能让着两个子线程能顺序的执行? 答案自然是用join来使得两个线程顺序执行,先看一下具体代码 public class ThreadOfJoi ...

  3. java wait 参数_java中wait()和join()方法的区别是什么

    java中wait()和join()方法的区别是:存在不同的java包中:wait()方法用于线程间通信,它所施加的等待状态的线程可以被启动:join()方法用于在多个线程之间添加排序,它所施加的等待 ...

  4. Thread的join方法

    Thread中的join方法主要的作用是让jion的线程加入当前线程,等加入的线程执行完之后才会执行当前线程. 接下来看个例子: public class TestJoin {public stati ...

  5. java有push方法么_[Java教程]js中push和join方法使用介绍

    [Java教程]js中push和join方法使用介绍 0 2013-10-09 07:00:17 push和join方法想必大家并不陌生吧,在本文将为大家详细介绍下js中的push和join方法的使用 ...

  6. java线程 yield_Java线程中yield与join方法的区别

    长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...

  7. Thread的join方法使用解析

    在C#中,Thread用的是比较多的,至少在windows form中使用是比较频繁的.一说到线程,可能马上就会想到界面和线程交互的头疼事,多线程之前数据共享,线程异步等等.这些当然是比较头疼的,只要 ...

  8. python sleep和wait_多线程中sleep()、wait()方法等的区别

    1.这两个方法来自不同的类分别是Thread和Object 2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法. 3.wait,notify和noti ...

  9. 关于多线程中sleep、join、yield的区别

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 Good friends are like stars. You don't ...

最新文章

  1. cbow 和skip-gram比较
  2. iptables规则的查看、添加、插入、删除和修改
  3. AIX 查看进程的内存使用情况
  4. 学习鸟哥的Linux私房菜笔记(3)——基础使用
  5. 用JavaScript玩转计算机图形学(一)光线追踪入门
  6. windbg学习.formats--转换成各种进制
  7. mysql时间区间效率_对于sql中使用to_timestamp判断时间区间和不使用的效率对比及结论...
  8. 虚拟ip weblogic服务器,虚拟IP是什么
  9. C++socket编程(一):绪论
  10. k8s核心技术-持久化存储(PV和PVC)---K8S_Google工作笔记0051
  11. python字典api_python接口自动化(九)--python中字典和json的区别(详解)
  12. CISA 发布关于 Treck TCP/IP 栈中新漏洞的 ICS 安全公告
  13. linux less 阻塞输出,linux – `less`命令显示输出所用的时间
  14. 简述使jdbc连接mysql数据库_java中简述使用JDBC完成数据库操作的基本步骤。
  15. ZZH:魔兽世界之000:MPQ
  16. 数据库创建图书馆管理系统
  17. DX11编程(一):DX和Effect的基本配置和属性表配置
  18. shell脚本的逻辑判断
  19. Buildroot笔记
  20. PDF文件转换文件格式

热门文章

  1. 分布式系统中的通信机制
  2. 中科院+华为,我们能得到什么?
  3. 手机上如何制作gif动画?三步教你手机gif制作
  4. 华为eNSP的基于MAC地址划分VLAN
  5. java之map函数详细分析(全)
  6. 生活的哲理,让自己更淡定
  7. Oracle 9i,sqlplus,Oracle9i iSQL*PLUS的配置过程
  8. 运动耳机防水怎么样?推荐六款运动党必备的防水耳机
  9. JVM-垃圾回收算法CMS和G1
  10. web项目测试总结要点及测试方法