一般用join方法实现主线程等待其他异步线程完成,今天就看看它到底是咋实现的。
先看下示例
// 子线程
static class SleepThread implements Runnable {
@Override
public void run() {
try {
System.out.println("子线程开始");
Thread.sleep(1000);
System.out.println("子线程结束");
} catch (InterruptedException e) {
// 忽略异常
}
}
}
public static void main(String[] args) {
try {
Thread t1 = new Thread(new SleepThread());
// 开启子线程
t1.start();
// 让主线程main等待子线程t1
t1.join();
System.out.println("main over");
} catch (Exception e) {
e.printStackTrace();
}
这就是一般join方法的用法了。执行t1.join();
后,主线程会在此处等待t1线程完成后再执行。来看看join()
源码,分析下怎么实现的。
// Thread
public final void join() throws InterruptedException {
join(0);
}
接着往下看
// 注意join方法有synchronized修饰
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) {
// 主要是这里,不断判断是否存在,如果存活就调用wait
// 下面看看它怎么判断存活的
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
isAlive方法
//是个native方法
public final native boolean isAlive();
由上面可知,执行了join()方法后,就获得了该线程实例的synchronized锁(在例子中是t1),随后调用wait()方法进入等待状态。
关键是什么时会唤醒,谁会唤醒它的。
join方法注释上有
As a thread terminates the * {@code this.notifyAll} method is invoked
也就是说JVM会保证,当线程终结时,会调用notifyAll()方法唤醒所有等待该实例锁的对象。由此,join()机制就算是搞懂了。
不过,既然知道了join的机制,我们也可以实践一下
public static void testJoin() throws InterruptedException {
// t1线程会等待2秒
Thread t1 = new Thread(new SleepThread());
t1.start();
// 获取t1的锁
synchronized (t1) {
//进入等待状态,等待t1结束唤醒它
t1.wait();
}
System.out.println("main end");
}
与源码join有不一样的地方,没有加isAlive的判断,没有用循环,如果你的程序没有在别的地方用t1这个锁,也没有地方用类似t1.notify
或t1.notifyAll
的地方,那上面就可以。不过为了保险,还是用下面这个吧
public static void testJoin() throws InterruptedException {
// t1线程会等待2秒
Thread t1 = new Thread(new SleepThread());
t1.start();
synchronized (t1) {
// 用循环而不是if,也是为了防止其他地方唤醒了t1,而不是当t1线程结束的时候,即防止假唤醒
while (t1.isAlive()) {
t1.wait();
}
}
System.out.println("main end");
}