简体   繁体   English

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

[英]How does JVM notify a thread blocked by `join()`?

The join() method waits for a thread to die. join()方法等待线程死亡。 it use wait to do this. 它使用wait来做到这一点。

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

So when the thread exits, how can it notify threads in wait set. 因此,当线程退出时,如何通知等待集中的线程。

  1. I try to find code in JDK source code, but failed. 我尝试在JDK源代码中找到代码,但是失败了。 Can anyone show me the relevant code snippets? 谁能告诉我相关的代码片段?

  2. when a thread in wait set, it may check isAlive() so many times for its timeslice, is this a waste? 当线程处于等待状态时,它可能会多次检查isAlive()的时间片,这是浪费吗?

  3. if isAlive() is false, it just return, that thread is already in wait set. 如果isAlive()为false,则仅返回该线程已处于等待状态。 Is the while(isAlive()) necessary? while(isAlive())必要?

1) I try to find code in JDK source code, but failed. 1)我尝试在JDK源代码中查找代码,但是失败了。 Can anyone show me the relevant code snippets? 谁能告诉我相关的代码片段?

The pathname for the Thread class in the OpenJDK jdk8u source tree is jdk/src/share/classes/java/lang/Thread.java . OpenJDK jdk8u源树中Thread类的路径名是jdk/src/share/classes/java/lang/Thread.java The code for join() is below. join()的代码如下。

The native code where the notifyAll occurs is in Thread::exit in hotspot/src/share/vm/runtime/thread.cpp . notifyAll发生的本机代码位于hotspot/src/share/vm/runtime/thread.cpp Thread::exit中。

For other releases the paths may be different. 对于其他版本,路径可能不同。 (The find command is your friend.) find命令是您的朋友。)

2) When a thread in wait set, it may check isAlive() so many times for its timeslice, is this a waste? 2)当线程处于等待状态时,它可能多次检查isAlive()的时间片,这是浪费吗?

That is incorrect. 那是不对的。

  • The "wait set" argument is incorrect. “等待集”参数不正确。 If the current thread can call isAlive() it is not in any wait set. 如果当前线程可以调用isAlive() ,则它不在任何等待集中。 It will only be in the "wait set" for the target Thread when it is in a wait(...) call. 仅在目标Thread处于wait(...)调用中时,它才位于目标Thread的“等待集”中。 It is removed from the "wait set" when the current thread is notified. 通知当前线程时,将其从“等待集”中删除。

    To reiterate, a thread t1 is in the "wait set" of another thread t2 when t1 is executing t2.wait(...) . 重申一下,当t1执行t2.wait(...)时,线程t1位于另一个线程t2的“等待集”中。

  • A wait(...) call with a zero timeout means "wait until notified without a timeout ". 零超时的wait(...)调用的意思是“等待直到收到通知而没有超时 ”。 Therefore, this is not a busy loop. 因此,这不是一个繁忙的循环。

  • The loop will usually go around zero or one time only. 循环通常只会出现零或一次。 (But see the next part of my answer.) (但请参阅我的答案的下一部分。)

3) If isAlive() is false, it just return, that thread is already in wait set. 3)如果isAlive()为false,则仅返回该线程已处于等待状态。 Is the while(isAlive()) necessary? while(isAlive())是否必要?

  • Your "wait set" logic is incorrect (as above). 您的“等待设置”逻辑不正确(如上所述)。

  • The loop is necessary. 循环是必要的。 It is possible for any application code that has a reference to the target Thread object to call Object.notify() on that it. 任何引用目标Thread对象的应用程序代码都可以对其调用Object.notify() That causes the wait(0) to return. 这导致wait(0)返回。 But since this "wake up" is spurious, it is necessary to check that the target Thread has actually ended (by calling isAlive() ) and maybe waitinf again. 但是由于这种“唤醒”是虚假的,因此有必要检查目标Thread是否实际结束(通过调用isAlive() ),并可能再次等待。

    This could happen repeatedly ... if application code is doing something silly ... but it shouldn't. 如果应用程序代码在做一些愚蠢的事情,这可能会反复发生……但事实并非如此。


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;
        }
    }
}

Most of the implementation of Thread is in native code. Thread大多数实现是在本机代码中进行的。 That is where the notifyAll that wakes up the joining threads is made. 那是唤醒连接线程的notifyAll地方。

To answer your questions: 要回答您的问题:

  1. wait() is a native method and uses System code. wait()是本机方法,并使用系统代码。 There is no Java code for that. 没有为此的Java代码。

  2. wait() is not a means to wait for a Thread but to synchronize on a certain object. wait()不是等待线程的方法,而是在某个对象上进行同步的方法。 Wait() is the wrong method to pause a thread, you need to use sleep(). Wait()是暂停线程的错误方法,您需要使用sleep()。

  3. The counterpart of wait() is notify() or notifyAll(). wait()的对应对象是notify()或notifyAll()。 This will wake up Threads which wait for the calling object. 这将唤醒等待调用对象的线程。 Wait() and notify are part of the Object.class and need a synchronization on the object. Wait()和notify是Object.class的一部分,需要在对象上进行同步。

A Thread is alive as long as its run method is executing. 只要线程的run方法正在执行,它就是活动的。 If you join a thread the calling thread will automatically halt. 如果您加入一个线程,则调用线程将自动停止。 If you want to let a thread wait then use Thread.sleep. 如果要让线程等待,请使用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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM