代码实战
简单创建一个t1线程,sleep 1s 模拟线程工作
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(() -> {
System.out.println("t1 start");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end");
});
t1.start();
t1.join();
System.out.println("main thread doSth...");
我们都知道在调用了t1.join()方法之后,主线程会等待t1线程结束,才会继续往下运行代码输出内容
Thread类中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;
}
}
}
由于延时等待部分实现原理与无限期等待类似,提取重点代码为:
while (isAlive()) {
wait(0);
}
等价于
while (t1.isAlive()) {
t1.wait(0);
}
isAlive() 方法为Thread的方法,用于判断一个Thread实例是否存活,在此处用于判断t1是否存活,
若t1存活, 则调用t1的wait(0)方法使得main线程wait
疑惑问题
可能有些同学有疑问:为什么在判断t1存活,调用t1.wait()之后 wait的是main线程而不是t1呢?
注意!!! 这里并非是t1线程wait, 虽然t1.wait()很具有迷惑性,很容理解为是t1去wait, 但wait是Object对象的方法, t1在这里仅作为锁对象,t1的Monitor提供waitSet的功能, 真正wait的是调用 t1.join()方法的main线程
后续唤醒
问: 为什么在t1线程结束之后, 源码中并未看到在哪唤醒了main线程 ?
答: 当 Thread 执行完毕之后会调用 notifyAll() 方法,不过不是在 Java 源码中调用的,而是在 jdk 的 native code 里调用的。
src/hotspot/share/runtime/thread.cpp
void Thread::call_run() {
...
this->pre_run();
this->run();
this->post_run();
...
}
void JavaThread::post_run() {
this->exit(false);
...
}
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
...
ensure_join(this);
...
}
static void ensure_join(JavaThread* thread) {
...
//
lock.notify_all(thread);
...
}
可见在线程exit之后, JVM会调用notify_all()方法唤醒线程