join方法通常用来做同步操作,如果线程1在线程2之后执行,就可以在线程1中调用线程2.join()方法来实现。实际上这个操作我们用wait/notify也是可以实现的。
@Slf4j
public class Demo {
private static Demo lock = new Demo();
public static void main(String[] args) throws Throwable {
new Thread(() -> {
synchronized (lock) {
try {
log.info("我是线程1,我需要先执行");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notifyAll();
}
}).start();
synchronized (lock) {
lock.wait();
}
log.info("我是线程2,我需要在线程1之后执行");
}
}
结果
09:25:55.705 com.ailik.d1.wait_notify.Demo [Thread-0] - 我是线程1,我需要先执行
09:25:57.709 com.ailik.d1.wait_notify.Demo [main] - 我是线程2,我需要在线程1之后执行
进程已结束,退出代码为 0
接下来使用join方法实现
@Slf4j
public class Demo {
@SneakyThrows
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
log.info("我是线程1,我需要先执行");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t1.join();
log.info("我是线程2,我需要在线程1之后执行");
}
}
实际上join()方法内部同样是wait/notify的操作。接下来我们来看一下join()的源码(这里只贴重要部分)
public final synchronized void join(long millis)
while (isAlive()) {
wait(0);
}
}
从源码中我们可以得到的以下信息
1、这是一个同步方法(同步锁是线程对象,也就是线程2的线程对象)
2、里面调用了wait方法,wait方法作用是使当前线程进入锁对象的等待池(注意:当前线程是线程1。因为代码是在线程1中调用的join方法)
线程1调用join方法后,会被wait方法阻塞,但是似乎并没有一个可以唤醒线程1的notify方法。但是从效果来看,这个notify方法应该是存在的。之后我又通过查询资料,最后去翻看jdk源码发现确实线程结束之后调用了notifyAll方法(这里也是只贴关键方法)
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
ensure_join(this);
}
static void ensure_join(JavaThread* thread) {
lock.notify_all(thread);
}
那么就结案了
线程1调用线程2.join()方法后会被阻塞,同步锁是线程2对象。当线程2执行完后又会调用notifyAll来唤醒线程2等待池中的所有线程对象