JVM 如何通知被“join()”阻塞的线程?

wxw*_*wxw 2 java multithreading jvm notify

join()方法等待线程终止。它用来wait执行此操作。

if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        }
Run Code Online (Sandbox Code Playgroud)

那么当线程退出时,如何通知wait set中的线程呢?

  1. 我尝试在JDK源代码中查找代码,但失败了。谁能告诉我相关的代码片段吗?

  2. 当一个线程处于等待状态时,它可能会isAlive()多次检查其时间片,这是浪费吗?

  3. 如果isAlive()为 false,则返回,该线程已处于等待集中。有while(isAlive())必要吗?

Ste*_*n C 5

  1. 我尝试在JDK源代码中查找代码,但失败了。谁能告诉我相关的代码片段吗?

ThreadOpenJDK jdk8u 源代码树中该类的路径名是jdk/src/share/classes/java/lang/Thread.java。代码join()如下。

发生该情况的本机代码notifyAll位于.Thread::exithotspot/src/share/vm/runtime/thread.cpp

对于其他版本,路径可能不同。(find命令是你的朋友。)

  1. 当一个线程处于等待状态时,它可能会isAlive()多次检查其时间片,这是浪费吗?

这是不正确的。

  • “等待设置”参数不正确。如果当前线程可以调用,则isAlive()它不在任何等待集中。Thread仅当目标处于通话状态时,它才会处于目标的“等待集”中wait(...)。当通知当前线程时,它将从“等待集合”中删除。

    重申一下,一个线程在执行时t1处于另一个线程的“等待集中” 。t2t1t2.wait(...)

  • 呼叫wait(0)意味着“等待通知,没有超时”。sleep(0)(它与or的意思不同yield()!)因此,这不是一个繁忙的循环。

  • 该循环通常只会进行零次或一次。(但请参阅我答案的下一部分。)

  1. 如果 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

的大部分实现Thread都是在本机代码中。这就是notifyAll唤醒连接线程的地方。