join()
方法等待线程死亡。它使用wait
来做到这一点。
if (millis == 0) {
while (isAlive()) {
wait(0);
}
}
因此,当线程退出时,如何通知等待集中的线程。
我尝试在JDK源代码中查找代码,但是失败了。谁能给我看看相关的代码片段?
当线程进入等待集时,它可能会多次检查isAlive()
的时间片,这是浪费吗?
如果isAlive()
为假,则仅返回该线程已处于等待状态。 while(isAlive())
是否必要?
答案 0 :(得分:4)
1)我尝试在JDK源代码中找到代码,但是失败了。谁能给我看看相关的代码片段?
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 等待集中。仅在目标Thread
处于调用中时,它才会在目标wait(...)
的“等待集”中。通知当前线程时,将其从“等待集”中删除。
重申一下,当t1
执行t2
时,线程t1
在另一个线程t2.wait(...)
的“等待集”中。
一个wait(...)
超时为零的调用意味着“等待直到收到通知没有超时”。因此,这不是一个繁忙的循环。
循环通常 大约为零或一次。 (但请参阅我的答案的下一部分。)
3)如果isAlive()为false,则仅返回该线程已处于等待状态。 while(isAlive())是否必要?
您的“等待设置”逻辑不正确(如上所述)。
循环是必要的。引用目标Thread
对象的任何应用程序代码都可以在其上调用Object.notify()
。这导致wait(0)
返回。但是由于这种“唤醒”是虚假的,因此有必要检查目标Thread
是否实际上已经结束(通过调用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
所在的地方。
答案 1 :(得分:0)
要回答您的问题:
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();