结论:A 线程调用 B 线程对象的 join 方法,则 A 线程会被阻塞,直到 B 线程 挂掉 (Java Doc 原话: Watis for this thread to die)。
一、分析
查看源代码:
public final void join() throws InterruptedException {
join(0); //得接着看这个带参数的方法,这里传入 0 表示等待时间为永久
}
带参数的 join:
public final synchronized void join(long millis) // 注意这里的 synchronized 关键字,A 线程 获取了 B 线程对象的锁,所以下面的代码中才可以调用 wait 方法
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) { // 参数为 0
while (isAlive()) { // 等到死为止
wait(0); // 这是 Object 对象的 wait 方法,调用了这个方法的线程(A 线程)会阻塞
}
} else { // 等待参数指定的时间
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
到这里,基本可以得出开头的结论了。
但是,开头的结论并不十分严谨,因为线程 A 其实并不是一直阻塞直到线程 B 挂掉的:
while (isAlive()) { wait(0); //真正让线程 A 阻塞的是这个方法的调用 }
当 进入 wait(0) 时,线程 A 阻塞,但 wait(0) 返回时,线程 A 唤醒,但是 while 循环条件如果满足的话 (线程 B 还没死),线程 A 再次阻塞。
线程 A 一直在 join 方法里,在阻塞和唤醒之间不断切换状态,直到线程 B 挂掉。
二、应用场景
为什么要让线程 A 阻塞,直到线程 B 挂掉呢?
假如:线程 B 在做一个耗时的计算,线程 A 需要这个计算的结果,并且线程 A 没有其他事要做了,只想得到计算结果,那么线程 A 就可以 调用线程 B 对象 的 join 方法,
让自己阻塞,等线程 B 挂掉(计算结束),取得计算结果。