Thread.join
加了join,表示join的线程的修改对于join之外的代码是可见的。
代码示例:
public class JoinDemo {
private static int i = 1000;
public static void main(String[] args) {
new Thread(()->{
i = 3000;
}).start();
System.out.println("i="+i);
}
}
我们在main线程中定义一个i
,初始值为1000。
在main方法中创建一个线程,将i值设置为3000,启动线程。
然后main方法打印 i
的值。
请问,i
值为多少?
我们执行后的输出结果为:
i=1000
这是由于main线程先于thread线程,所以输出的i
值为1000。
如果我们希望 Thread线程中的执行结果对main线程可见,怎么办?
使用 thread.join()
,如下所示:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
i = 3000;
});
thread.start();
thread.join();
System.out.println("i="+i);
}
执行结果:
i=3000
所以说,如果我们希望结果是可见的话,可以通过join来做。
那么join的实现原理是什么?请看下图:
main线程中,创建了一个线程t1;
t1.start() 启动线程;
t1线程修改了i
的值为3000;而且让修改可见。说明t1线程阻塞的main线程,使它无法打印。
t1线程继续执行直到终止。
t1终止后,去唤醒被它阻塞的线程。main线程继续执行,打印出 i=3000
。
有阻塞,就一定要唤醒,否则线程无法释放。我们是怎么触发唤醒的?
我们进入join的源码:
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是个synchronized的方法,里面有个 wait(0)
方法来阻塞。
那它是如何唤醒的呢?
我们去看hotspot的源码,其中的thread.cpp:
// For any new cleanup additions, please check to see if they need to be applied to
// cleanup_failed_attach_current_thread as well.
v