Как JVM уведомляет поток, заблокированный `join ()`? - PullRequest
2 голосов
/ 08 мая 2019

Метод join() ожидает смерти потока.для этого он использует wait.

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

Итак, когда поток завершается, как он может уведомить потоки в наборе ожидания.

  1. Я пытаюсь найти код в исходном коде JDK, но не получилось.Может кто-нибудь показать мне соответствующие фрагменты кода?

  2. , когда поток в установленном ожидании, он может проверить isAlive() столько раз для своего временного интервала, это пустая трата?

  3. если isAlive() имеет значение false, он просто возвращает, что поток уже находится в состоянии ожидания.Нужно ли while(isAlive())?

Ответы [ 2 ]

4 голосов
/ 08 мая 2019

1) Я пытаюсь найти код в исходном коде JDK, но не получилось.Может кто-нибудь показать мне соответствующие фрагменты кода?

Путь к классу Thread в дереве исходных текстов OpenJDK jdk8u - jdk/src/share/classes/java/lang/Thread.java.Код для join() приведен ниже.

Собственный код, где встречается notifyAll, находится в Thread::exit в hotspot/src/share/vm/runtime/thread.cpp.

Для других выпусков пути могут отличаться.(Команда find - ваш друг.)

2) Когда поток в наборе ожидания установлен, он может столько раз проверять isAlive() свой временной интервал, это пустая трата?

Это неверно.

  • Неверный аргумент "set wait".Если текущий поток может вызвать isAlive(), он не находится в любом установленном ожидании.Он будет только в «наборе ожидания» для цели Thread, когда он находится в wait(...) вызове.Он удаляется из «набора ожидания», когда текущий поток уведомляется.

    Повторюсь, поток t1 находится в «наборе ожидания» другого потока t2, когда t1 выполняется t2.wait(...).

  • Вызов wait(...) с нулевым тайм-аутом означает «дождаться уведомления без тайм-аута ».Следовательно, это не занятый цикл.

  • Цикл будет обычно вращаться вокруг нуля или только один раз.(Но смотрите следующую часть моего ответа.)

3) Если isAlive () имеет значение false, он просто возвращает, этот поток уже находится в состоянии ожидания.Требуется ли while (isAlive ())?

  • Ваша логика "установки ожидания" неверна (как указано выше).

  • Цикл необходим.Для любого кода приложения, имеющего ссылку на целевой объект Thread, можно вызвать Object.notify() для него.Это заставляет wait(0) вернуться.Но так как это «пробуждение» является ложным, необходимо проверить, что цель Thread действительно закончилась (вызывая isAlive()) и, возможно, снова waitinf.

    Это может происходить многократно ... если код приложения делает что-то глупое ... но это не должно быть.


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, который пробуждает присоединяющиеся нити.

0 голосов
/ 08 мая 2019

Чтобы ответить на ваши вопросы:

  1. wait () является нативным методом и использует системный код. Для этого нет Java-кода.

  2. wait () - это не средство ожидания потока, а синхронизация с определенным объектом. Wait () - неправильный метод для приостановки потока, вам нужно использовать sleep ().

  3. Аналогом 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();
...