Java join()使用及源码分析
(先铺垫下,最后上源码)
首先再说一下join()方法的作用:若在父线程main中创建了一个子线程son,如果父线程需要等待子线程执行完再执行,则在父线程main中调用son.join();即可
官方解释:join() method suspends the execution of the calling thread until the object called finishes its execution.
即:son.join()方法阻塞调用此方法的线程(calling thread),直到线程son完成,此线程(main)再继续
还有几点需要注意
- wait()方法调用后会释放锁,并阻塞当前线程,等待notify。
- notify()方法调用后并不会释放锁。
- wait() notify()方法都必须在同步的代码中调用。
关于jion()的简单例子
public class JoinDemo {
public static void main(String[] args) {
try {
System.out.println("main running");
SonThread sonThread = new SonThread();
sonThread.start();
System.out.println("main suspend and waiting for son");
sonThread.join();
System.out.println("son did his work, main running");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SonThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("son running ..." + i);
}
}
}
/** 输出:
main running
main suspend and waiting for son
son running ...0
son running ...1
son running ...2
son running ...3
son running ...4
son did his work, main running
**/
可以看到main线程阻塞并等到son线程完成后才继续执行了。
join()源码如下:
public final void join() throws InterruptedException {
join(0);//调用下面的方法
}
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()内部是调用了wait()方法的。
接着分析下,
上面的例子中是通过sonThread.join();这段代码调用了join()的,join()是一个synchronize方法,其锁对象也就是this,在上面的例子中,也就是sonThread对象。所以sonThread.join()其实就相当于如下:
public class JoinDemo {
public static void main(String[] args) {
//...
synchronized (sonThread){
sonThread.wait();
//...
}
//...
}
}
再返回上面说的:wait()方法调用后会释放锁,并阻塞当前线程
那么当前线程是哪个线程呢?
join()的调用位于main Thread的main()中,所以这里当然就是阻塞main Thread了。所以sonThread.join()调用后,main Thread会阻塞起来。
那么main Thread被阻塞后是在哪收到notify而继续运行的呢?你可能在源码中找不到是哪notify了。
其实,这个过程涉及到了JVM底层了。son线程执行完毕了exit过程会有一个notifyall操作
以上面的例子来最后总结一下:sonThread.join() 这个调用表示mainThread将在锁对象sonThread上进行wait()等待,直到sonThread线程运行完成后mainThread才会收到通知被唤醒,然后继续执行。