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

时间:2019-05-08 12:30:13

标签: java multithreading join jvm notify

join()方法等待线程死亡。它使用wait来做到这一点。

if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        }

因此,当线程退出时,如何通知等待集中的线程。

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

  2. 当线程进入等待集时,它可能会多次检查isAlive()的时间片,这是浪费吗?

  3. 如果isAlive()为假,则仅返回该线程已处于等待状态。 while(isAlive())是否必要?

2 个答案:

答案 0 :(得分:4)

  

1)我尝试在JDK源代码中找到代码,但是失败了。谁能给我看看相关的代码片段?

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

发生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)

要回答您的问题:

  
      
  1. wait()是本机方法,并使用系统代码。没有为此的Java代码。

  2.   
  3. wait()不是等待线程,而是在特定对象上同步的方法。 Wait()是暂停线程的错误方法,您需要使用sleep()。

  4.   
  5. wait()的对应对象是notify()或notifyAll()。这将唤醒等待调用对象的线程。 Wait()和notify是Object.class的一部分,需要在对象上进行同步。

  6.   

只要线程的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();