Thread.join方法的解析(转)
原文链接:https://www.cnblogs.com/huangzejun/p/7908898.html
1. join() 的示例和作用
1.1 示例

- 1 // 父线程
- 2 public class Parent extends Thread {
- 3 public void run() {
- 4 Child child = new Child();
- 5 child.start();
- 6 child.join();
- 7 // ...
- 8 }
- 9 }


- 1 // 子线程
- 2 public class Child extends Thread {
- 3 public void run() {
- 4 // ...
- 5 }
- 6 }

上面代码展示了两个类:Parent(父线程类),Child(子线程类)。
在 Parent.run() 中,通过 Child child = new Child(); 新建 child 子线程(此时 child 处于 NEW 状态);
然后再调用 child.start()(child 转换为 RUNNABLE 状态);
再调用 child.join()。
在 Parent 调用 child.join() 后,child 子线程正常运行,Parent 父线程会等待 child 子线程结束后再继续运行。
下图是我总结的 Java 线程状态转换图:
1.2 join() 的作用
让父线程等待子线程结束之后才能继续运行。
我们来看看在 Java 7 Concurrency Cookbook 中相关的描述(很清楚地说明了 join() 的作用):
Waiting for the finalization of a thread
In some situations, we will have to wait for the finalization of a thread. For example, we may have a program that will begin initializing the resources it needs before proceeding with the rest of the execution. We can run the initialization tasks as threads and wait for its finalization before continuing with the rest of the program. For this purpose, we can use the join() method of the Thread class. When we call this method using a thread object, it suspends the execution of the calling thread until the object called finishes its execution.
当我们调用某个线程的这个方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。
2. join() 源码分析
以下是 JDK 8 中 join() 的源码:

- 1 public final void join() throws InterruptedException {
- 2 join(0);
- 3 }
- 4
- 5 public final synchronized void join(long millis)
- 6 throws InterruptedException {
- 7 long base = System.currentTimeMillis();
- 8 long now = 0;
- 9
- 10 if (millis < 0) {
- 11 throw new IllegalArgumentException("timeout value is negative");
- 12 }
- 13
- 14 if (millis == 0) {
- 15 while (isAlive()) {
- 16 wait(0);
- 17 }
- 18 } else {
- 19 while (isAlive()) {
- 20 long delay = millis - now;
- 21 if (delay <= 0) {
- 22 break;
- 23 }
- 24 wait(delay);
- 25 now = System.currentTimeMillis() - base;
- 26 }
- 27 }
- 28 }
- 29
- 30 public final synchronized void join(long millis, int nanos)
- 31 throws InterruptedException {
- 32
- 33 if (millis < 0) {
- 34 throw new IllegalArgumentException("timeout value is negative");
- 35 }
- 36
- 37 if (nanos < 0 || nanos > 999999) {
- 38 throw new IllegalArgumentException(
- 39 "nanosecond timeout value out of range");
- 40 }
- 41
- 42 if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
- 43 millis++;
- 44 }
- 45
- 46 join(millis);
- 47 }

我们可以看到 join() 一共有三个重载版本(都是 final method,无法被子类覆盖):
- 1 public final void join() throws InterruptedException;
- 2
- 3 public final synchronized void join(long millis) throws InterruptedException;
- 4
- 5 public final synchronized void join(long millis, int nanos) throws InterruptedException;
其中
a. join() 和 join(long millis, int nanos) 最后都调用了 join(long millis)。
b. 带参数的 join() 都是 synchronized method。
c. join() 调用了 join(0),从源码可以看到 join(0) 不断检查当前线程(join() 所属的线程实例,非调用线程)是否是 Active。
d. join() 和 sleep() 一样,都可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会出让锁,而 sleep() 会一直保持锁。
以本文开头的代码为例,我们分析一下代码逻辑:
Parent 调用 child.join(),child.join() 再调用 child.join(0) (此时 Parent 会获得 child 实例作为锁,其他线程可以进入 child.join() ,但不可以进入 child.join(0), 因为无法获取锁)。child.join(0) 会不断地检查 child 线程是否是 Active。
如果 child 线程是 Active,则循环调用 child.wait(0)(为了防止 Spurious wakeup, 需要将 wait(0) 放入 for 循环体中;此时 Parent 会释放 child 实例锁,其他线程可以竞争锁并进入 child.join(0)。我们可以得知,可以有多个线程等待某个线程执行完毕)。
一旦 child 线程不为 Active (状态为 TERMINATED), child.join(0) 会直接返回到 child.join(), child.join() 会直接返回到 Parent 父线程,Parent 父线程就可以继续运行下去了。
超下来,说不定下次会看看,为别人引一点流,哈哈
Thread.join方法的解析(转)的更多相关文章
- Thread.join()方法
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B.t.join() ...
- Java Thread.join()方法
一.使用方式. join是Thread类的一个方法,启动线程后直接调用,例如: Thread t = new AThread(); t.start(); t.join(); 二.为什么要用join() ...
- JAVA THREAD.JOIN方法详解
一.使用方式. join是Thread类的一个方法,启动线程后直接调用,例如: Thread t = new AThread(); t.start(); t.join(); 二.为什么要用join() ...
- 多线程--Thread.join方法
在Thread类的Api中,Join的作用是让当前线程等待目标线程结束之后才继续执行. thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程. 比如在线程B ...
- Java java.lang.Thread#join()方法分析
结论:A 线程调用 B 线程对象的 join 方法,则 A 线程会被阻塞,直到 B 线程 挂掉 (Java Doc 原话: Watis for this thread to die). 一.分析 查看 ...
- thread.join() 方法存在的必要性是什么?
好久远的问题,为什么关注这个问题的人这么少? 或许是用到这个功能的情形比较少吧. 1.等待处理结果 为什么要用join()方法在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算 ...
- Thread join方法的用途
主线程中会创建多个子线程做一些事情,主线程要用到这些子线程处理的数据,因此它需要等待所有的子线程处理完之后才继续运行.这就要用到join方法了.
- 浅析Thread的join() 方法
Thread中的 join() 方法在实际开发过程中可能用的不是很多,但是在面试中作为考察基本功知识的扎实与否,经常会被用到.因此,对于 Thread 的 join() 方法进行了一定的研究. 常见的 ...
- Thread的join方法
一个线程在执行的过程中,可能调用另一个线程,前者可以称为调用线程,后者成为被调用线程. Thread.Join方法的使用场景:调用线程挂起,等待被调用线程执行完毕后,继续执行. 如下案列: 当NewT ...
随机推荐
- 【Linux】linux常用查看命令
查看磁盘大小的命令df .du df -h 查看整台服务器的硬盘使用情况 du -sh * 查看每个文件夹的大小 ps -ef 查看所有进程 top 实时显示进程状态用户 free -m 查看内存使用 ...
- jquery判断设备是否是手机
//判断是否是手机 function IsMobile() { var isMobile = { Android: function () { return navigator.userAgent.m ...
- New Roads CodeForces - 746G (树,构造)
大意:构造n结点树, 高度$i$的结点有$a_i$个, 且叶子有k个. 先确定主链, 然后贪心放其余节点. #include <iostream> #include <algorit ...
- Windows自动登录设置 Windows免密登录
设置方法如下:开始-运行-control userpasswords2:打开用户账号管理页面,将“要使用本机,用户必须输入用户名和密码”前面的勾去掉:点击 应用,确定之后.会提示用户输入需要自动登陆系 ...
- 【基础知识】【1】CDN
正文: CDN:Content Delivery Network,内容分发网络.使用户访问离ta最近的资源服务器,优化访问速度 优点: 1,内容可以共享,不同站点的同一文件可以不用多次缓存 2,增加下 ...
- ACM基础(一)
比较大的数组应尽量声明在main函数外,否则程序可能无法运行. C语言的数组并不是“一等公民”,而是“受歧视”的.例如,数组不能够进行赋值操作: 在程序3-1中,如果声明的是“int a[maxn], ...
- 把springboot的项目打包运行指南
受到传统mvc模式的开发影响,多数人都会想到把springboot项目打成war包在服务器容器里运行,笔者试过很多种方法打成war包部署tomcat上运行.运行成功但是怎么也访问不了,一直报404的错 ...
- python-mongodb基本操作都在这了
数据库 增 use db1 #有则切换,无则新增 查 show dbs #查看所有 db #当前 删 db.dropDatabase() 集合: 增: db.user db.user.info db. ...
- hdu-2865-polya+dp+矩阵+euler函数
Birthday Toy Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- ORA-12537:TNS:connectionclosed错误处理过程
1.ORA-12537:TNS:connectionclosed错误处理过程 检查监听正常,oracle服务也是正常启动的,但是登录不进去. 2.解决方案 1. cd $ORACLE_HOME/bin ...