浅析Thread.join()
Posted Trace Spaces
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析Thread.join()相关的知识,希望对你有一定的参考价值。
概要
本文分为三部分对 hread.join() 进行分析:
1. join() 的示例和作用
// 主线程 public class Parent extends Thread { public void run() { Child child = new Child(); child .start(); child .join(); // ... } }
// 子线程 public class Child extends Thread { public void run() { // ... } }
上面代码中有两个类:Parent(主线程类),Child(子线程类)。
在 Parent.run() 中,通过 new Child() 新建 child 子线程(此时 child 处于 NEW 状态),然后调用 child.start()(child 转换为 RUNNABLE 状态),再调用 child.join()。
在 Parent 调用 child.join() 后,child 子线程正常运行,Parant 主线程会等待 child 子线程结束后再继续运行。
join() 的作用:让主线程等待子线程结束之后才能继续运行。
Java 7 Concurrency Cookbook 中的描述:
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() 有三个版本:
public final void join();
public final synchronized void join(long millis);
public final synchronized void join(long millis, int nanos);
其中 join() 和 join(long millis, int nanos) 最后都调用了 join(long millis)。
带参数的 join() 都为 synchronized method。
join() 说明
join() 调用了 join(0),从源码可以看到 join(0) 不断检查线程(join() 所属的线程实例,非调用线程)是否是 Active。
以本文开头的示例为例,Parent 调用 child.join(),child.join() 再调用 child.join(0) (此时 Parent 会获得 child 实例作为锁,其他线程可以进入 child.join() ,但不可以进入 child.join(0), 因为没有获得锁),child.join(0) 会不断地检查 child 线程是否是 Active。
如果是 Active,则不断地调用 child.wait(0)(此时 Parent 会释放 child 实例锁,其他线程可以竞争锁并进入 child.join(0))。我们可以得知,Parent 线程在不断地对 child.wait(0) 入栈和出栈。
一旦 child 线程不为 Active (状态为 TERMINATED), child.join(0) 会直接返回到 child.join(), child.join() 会直接返回到 Parent 主线程,Parent 主线程就可以继续运行下去了。
示意图:
Parent-------new Child()----RUNNING-----child.start()-----RUNNING----child.join()*****TIMED_WAITING******-----RUNNING-------TERMINATED | | | | | | | | | | | | Child`````````NEW``````````Child-------------------------RUNNING---------------------TERMINATED
3. 对网上其他分析 join() 的文章提出疑问
网上其他文章描述:
子线程结束之后,会“唤醒”主线程,主线程重新获取cpu执行权,继续运行。
“唤醒”令人误解。其实是主线程调用方法不断去检查子线程的状态, 这是个主动的动作。
以上是关于浅析Thread.join()的主要内容,如果未能解决你的问题,请参考以下文章