кто и когда уведомляет thread.wait(), когда вызывается thread.join()?

thread.join() позвонит thread.wait(), но кто и когда уведомит (с помощью thread.notify() или notifyAll()) thread.wait()?

Как мы знаем, присоединение к потоку будет ждать завершения потока, но кто вызывает уведомление об этом?


person jiafu    schedule 26.03.2012    source источник


Ответы (2)


Изменить:

О, вы говорите о самом объекте Thread. Внутри join() мы видим wait(). Что-то типа:

while (isAlive()) {
    wait(0);
}

notify() для этого обрабатывается подсистемой Thread. Когда метод run() завершается, notify() вызывается для объекта Thread. Я не уверен, можно ли увидеть код, который на самом деле вызывает notify() — похоже, это сделано в нативном коде.


Код пользователя не должен вызывать notify() для этого объекта Thread. Код Java Thread обрабатывает это внутри. Как только поток завершится, вызов join() вернется.

Например, следующий код будет выполняться нормально, а вызов join() будет возвращаться нормально без каких-либо вызовов wait() или notify().

Thread thread = new Thread(new Runnable() {
   public void run() {
      // no-op, just return immediately
   }
});
thread.start();
thread.join();

Важно отметить, что на это поведение, вероятно, не следует полагаться. Вызов notify() является внутренним для системы потоков. Вы должны использовать join(), если вы ждете завершения потока.

person Gray    schedule 26.03.2012
comment
3ks, но вы можете взглянуть на исходный код thread.class или отладить его с помощью fastdebug jdk, вы можете обнаружить, что при вызове join вы будете ждать в wait(). Так что я думаю, что вы ошибаетесь в этом вопросе. Но мой вопрос заключается в том, кто уведомляет об этом, ожидая внутри метода соединения. - person jiafu; 26.03.2012
comment
@jiafu Я отредактировал свой ответ. notify() вызывается из подсистемы Thread. Я не уверен, что вы видите этот код. Может быть, в родной стране. - person Gray; 26.03.2012
comment
Спасибо за ваше обновление. Как вы упомянули: когда метод run() завершается, метод notify() вызывается для объекта Thread. Это мой ожидаемый ответ. Но мы оба чувствуем, что я не уверен, можно ли увидеть код, который на самом деле вызывает notify(). Спасибо. ps: как вы узнали об этом. Когда метод run() завершается, метод notify() вызывается для объекта Thread. Я не могу найти какой-либо документ в Интернете, связанный с этой точкой зрения. ха-ха - person jiafu; 26.03.2012
comment
@jiafu Потому что так оно и работает. Код находится в цикле while: while (isAlive()) { wait(0); }. Он будет вызывать wait() до тех пор, пока поток не перестанет существовать. В конце метода run() собственный код устанавливает значение false и уведомляет метод Thread. - person Gray; 26.03.2012
comment
В конце метода run() собственный код устанавливает значение false и уведомляет вас, вы уверены? Я не могу разобраться с родным языком кода. Так что я не могу убедиться в этом. ЕСЛИ вы в этом уверены. Я тоже уверен. Большое вам спасибо! - person jiafu; 26.03.2012
comment
@jiafu Вот как это работает, чувак. зачем вам это знать? - person Gray; 26.03.2012
comment
Мне только это интересно. Как ты сказал. Мне незачем знать подробности. 3кс за ответ. Только сейчас я знаю то, что должен знать. - person jiafu; 26.03.2012
comment
@Jiafu есть поговорка: Select не сломан. Очень редко когда-либо возникает необходимость проверить правильность функционирования базовой части компьютерного языка. Oracle/Sun отвечают за модульное и регрессионное тестирование JDK/JRE. Так что нет необходимости проверять, что Thread#join действительно работает. - person Tim Bender; 02.04.2012
comment
Спасибо за теплое напоминание. - person jiafu; 06.04.2012

Что касается jdk7 для Linux, вы можете получить ответ из исходного кода openjdk.

/jdk7/hotspot/src/os/linux/vm/os_linux.cpp

int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);

static void *java_start(Thread *thread) {
  ...
  thread->run();
  return 0;
}

и при запуске потока в java поток будет экземпляром JavaThread.

/jdk7/hotspot/src/share/vm/runtime/thread.cpp

void JavaThread::run() {
  ...
  thread_main_inner();
}

void JavaThread::thread_main_inner() {
  ...
  this->exit(false);
  delete this;
}

void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
  ...
  // Notify waiters on thread object. This has to be done after exit() is called
  // on the thread (if the thread is the last thread in a daemon ThreadGroup the
  // group should have the destroyed bit set before waiters are notified).
  ensure_join(this);
  ...
}

static void ensure_join(JavaThread* thread) {
  // We do not need to grap the Threads_lock, since we are operating on ourself.
  Handle threadObj(thread, thread->threadObj());
  assert(threadObj.not_null(), "java thread object must exist");
  ObjectLocker lock(threadObj, thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
  // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
  // Clear the native thread instance - this makes isAlive return false and allows the join()
  // to complete once we've done the notify_all below
  java_lang_Thread::set_thread(threadObj(), NULL);
  lock.notify_all(thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
}

поэтому lock.notify_all(thread) уведомит все потоки, ожидающие завершения потока.

person DaSqy Stc    schedule 28.06.2017