【问题标题】:How does JVM notify a thread blocked by `join()`?JVM如何通知被`join()`阻塞的线程?
【发布时间】:2019-09-26 04:38:17
【问题描述】:
join() 方法等待线程终止。它使用wait 来执行此操作。
if (millis == 0) {
while (isAlive()) {
wait(0);
}
}
那么当线程退出时,它如何通知等待集中的线程。
我尝试在 JDK 源代码中查找代码,但失败了。谁能给我看一下相关代码sn-ps?
当一个线程处于等待集时,它可能会多次检查isAlive()的时间片,这是浪费吗?
如果isAlive() 为假,它只是返回,该线程已经处于等待设置中。 while(isAlive()) 有必要吗?
【问题讨论】:
标签:
java
multithreading
join
jvm
notify
【解决方案1】:
1) 我尝试在 JDK 源代码中查找代码,但失败了。谁能给我看一下相关代码sn-ps?
OpenJDK jdk8u 源代码树中Thread 类的路径名是jdk/src/share/classes/java/lang/Thread.java。 join() 的代码如下。
出现notifyAll 的本机代码在Thread::exit 中的hotspot/src/share/vm/runtime/thread.cpp 中。
对于其他版本,路径可能不同。 (find 命令是你的朋友。)
2) 当一个线程处于等待集时,它可能会多次检查isAlive() 的时间片,这是浪费吗?
这是不正确的。
-
“等待设置”参数不正确。如果当前线程可以调用isAlive(),则它不在any 等待集中。只有在 wait(...) 调用中时,它才会在目标 Thread 的“等待集”中。当通知当前线程时,它会从“等待集”中移除。
重申一下,当t1 正在执行t2.wait(...) 时,一个线程t1 处于另一个线程t2 的“等待集”中。
具有零超时的wait(...) 调用意味着“等待通知没有超时”。因此,这不是一个繁忙的循环。
循环通常只会绕零或绕一圈。 (但请参阅我的答案的下一部分。)
3) 如果 isAlive() 为假,它只是返回,该线程已经处于等待集合中。 while(isAlive()) 有必要吗?
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;
}
}
}
Thread 的大部分实现都在本机代码中。这就是唤醒连接线程的notifyAll 的位置。
【解决方案2】:
回答您的问题:
-
wait() 是本机方法并使用系统代码。没有 Java 代码。
-
wait() 不是等待线程的方法,而是在某个对象上进行同步。 Wait()是暂停线程的错误方法,需要使用sleep()。
-
wait() 的对应物是 notify() 或 notifyAll()。这将唤醒等待调用对象的线程。 Wait() 和 notify 是 Object.class 的一部分,需要在对象上进行同步。
只要它的 run 方法正在执行,一个线程就处于活动状态。如果你加入一个线程,调用线程将自动停止。
如果您想让线程等待,请使用 Thread.sleep。
Thread t1 = new Thread(){
public void run(){
try {
sleep(5000);
} catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("I'm done");
}
}
t1.start();
//The calling thread will wait here for 5 sec.
t1.join();