前言
在学习java中的并发的时候,很容易注意到一个函数join
,此函数的功能是等待指定的线程死亡或者经过指定的毫秒数,如果不指定毫秒数或者指定的毫秒数为空,则一直等待直到指定的线程死亡。JDK源码如下:
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
// 会检测线程是否存活,如果线程已经死亡则不需要等待
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
join()
就等价于join(0)
,join
函数的功能挺简单,不过在学习查阅资料的过程中,发现在等待的过程中,会影响到其它线程的工作状态,所以自己写了一个小demo测试了一下,最后总结出了join
更深层次的含义。
测试join函数
在下面的小demo中,我写了两个测试的线程,分别开启线程,观察输出。
public class JoinTest {
public static void main(String[] args) {
System.out.println("主线程开始执行");
Runnable r1 = () -> {
System.out.println("线程1开始执行");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println("线程1结束执行");
};
Runnable r2 = () -> {
System.out.println("线程2开始执行");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
System.out.println("线程2结束执行");
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
System.out.println("主线程结束执行");
}
}
----------输出结果----------
主线程开始执行
主线程结束执行
线程1开始执行
线程2开始执行
线程2结束执行
线程1结束执行
----------分析----------
主线程开始->线程1、线程2随机某个时点开始执行
(可能在主线程结束后,线程1、2结束时间点由开始时间和运行时长决定)->主线程结束执行
对于上面的demo,可以很明显的看出,在主线程执行的时候,开启了两个新线程,但是两个新线程的开始执行时间是随机的,而结束时间我人为设置了线程2会执行得更快。
public class JoinTest {
public static void main(String[] args) {
System.out.println("主线程开始执行");
......
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
}
t2.start();
System.out.println("主线程结束执行");
}
}
----------输出结果----------
主线程开始执行
线程1开始执行
线程1结束执行
主线程结束执行
线程2开始执行
线程2结束执行
----------分析----------
主线程开始->线程1随机某个时点开始执行->线程1结束执行->
主线程结束执行->线程2随机某个时点开始执行(可能在主线程结束前)->线程2结束执行
当主线程调用线程1的join()方法,主线程进入等待状态,直到线程1运行结束,主线程才由等待状态转为可执行状态,所以一定是在线程1结束后主线程才能结束执行。
public class JoinTest {
public static void main(String[] args) {
System.out.println("主线程开始执行");
......
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
try {
t2.join();
} catch (InterruptedException e) {
}
System.out.println("主线程结束执行");
}
}
----------输出结果----------
主线程开始执行
线程1开始执行
线程2开始执行
线程2结束执行
主线程结束执行
线程1结束执行
----------分析----------
主线程开始->线程1、线程2随机某个时点开始执行
(可能在主线程结束后,线程1、2结束时间点由开始时间和运行时长决定)->
线程2结束执行->主线程结束执行
同理,当主线程调用线程2的join()方法,主线程进入等待状态,直到线程2运行结束,主线程才由等待状态转为可执行状态,所以一定是在线程2结束后主线程才能结束执行。
总结
在A
线程中,使用B.join()
函数后会等待指定的线程死亡,然后继续运行,如果有其它线程C
其执行规则不变。