Вопрос-ответ

Difference between "wait()" vs "sleep()" in Java

Разница между "wait ()" и "sleep ()" в Java

В чем разница между wait() и sleep() в потоках?

Правильно ли я понимаю, что wait()-ing поток все еще находится в запущенном режиме и использует циклы процессора, но sleep()-ing не использует никаких циклов процессора?

Почему у нас есть оба wait() и sleep()?

Как меняется их реализация на более низком уровне?

Переведено автоматически
Ответ 1

A wait может быть "разбужен" другим потоком, вызывающим notify на ожидаемом мониторе, в то время как a sleep не может. Также waitnotify) должно происходить в блоке synchronized на объекте monitor, тогда как sleep этого не происходит:

Object mon = ...;
synchronized (mon) {
mon.wait();
}

На этом этапе текущий выполняющийся поток ожидает и освобождает монитор. Другой поток может выполнить

synchronized (mon) { mon.notify(); }

(на том же mon объекте) и первый поток (при условии, что это единственный поток, ожидающий на мониторе) проснется.

Вы также можете вызвать, notifyAll если на мониторе ожидают более одного потока – это разбудит их всех. Однако только один из потоков сможет захватить монитор (помните, что wait находится в synchronized блоке) и продолжить работу – остальные будут заблокированы до тех пор, пока они не смогут получить блокировку монитора.

Другой момент заключается в том, что вы вызываете wait on Object сам по себе (т. Е. Вы ожидаете на мониторе объекта), тогда как вы вызываете sleep on Thread.

Еще один момент заключается в том, что вы можете получать ложные пробуждения от wait (т. Е. Ожидающий поток возобновляется без видимой причины). Вы должны всегда wait выполнять некоторые условия следующим образом:

synchronized {
while (!condition) { mon.wait(); }
}
Ответ 2

Одно ключевое отличие, о котором еще не упоминалось, заключается в том, что:


  • sleep() не снимает блокировку, которую он удерживает в потоке,


    synchronized(LOCK) {
    Thread.sleep(1000); // LOCK is held
    }


  • wait() освобождает блокировку, которую он удерживает на объекте.


     synchronized(LOCK) {
    LOCK.wait(); // LOCK is not held
    }


Ответ 3

Я нашел этот пост полезным. Он показывает разницу между Thread.sleep(), Thread.yield() и Object.wait() человеческими терминами. Процитировать:


В конечном итоге все сводится к планировщику операционной системы, который распределяет временные интервалы между процессами и потоками.


sleep(n) говорит “Я закончил со своим таймшером, и, пожалуйста, не добавляйте мне еще один по крайней мере в течение n миллисекунд”. ОС даже не пытается запланировать спящий поток, пока не истечет запрошенное время.


yield() говорит “Я закончил со своим временным интервалом, но мне все еще нужно поработать”. ОС вольна немедленно предоставить потоку другой временной интервал или предоставить какой-либо другой поток или обработать процессор, от которого только что отказался производящий поток.


wait() говорит “Я закончил со своим таймшером. Не назначайте мне другой временной интервал, пока кто-нибудь не вызовет notify ().” Как и в случае с sleep(), ОС даже не попытается запланировать вашу задачу, пока кто-нибудь не вызовет notify() (или не произойдет один из нескольких других сценариев пробуждения).


Потоки также теряют остаток своего временного интервала при выполнении блокирующего ввода-вывода и при некоторых других обстоятельствах. Если поток работает через весь временной интервал, ОС принудительно берет управление на себя примерно так, как если бы был вызван yield(), чтобы могли выполняться другие процессы.


Вам редко требуется yield(), но если у вас приложение с большим объемом вычислений и логическими границами задач, вставка yield() может улучшить отзывчивость системы (за счет времени — переключение контекста, даже просто на ОС и обратно, не бесплатно). Как всегда, измеряйте и тестируйте в соответствии с целями, которые вас волнуют.


Ответ 4

Здесь много ответов, но я не смог найти семантическое различие, упомянутое ни в одном.

Дело не в самом потоке; требуются оба метода, поскольку они поддерживают очень разные варианты использования.

sleep() переводит поток в спящий режим, как это было раньше, он просто упаковывает контекст и прекращает выполнение на заранее определенное время. Итак, чтобы разбудить его раньше положенного времени, вам нужно знать ссылку на поток. Это не обычная ситуация в многопоточной среде. В основном используется для синхронизации по времени (например, пробуждение ровно через 3,5 секунды) и / или жестко запрограммированной справедливости (просто поспите некоторое время и позвольте другим потокам работать).

wait() Напротив, это механизм синхронизации потоков (или сообщений), который позволяет вам уведомлять поток, на который у вас нет сохраненной ссылки (и вам не нужно заботиться). Вы можете думать об этом как о шаблоне публикации-подписки (wait == подписаться и notify() == опубликовать). По сути, используя notify (), вы отправляете сообщение (которое может даже не быть получено вообще, и обычно вам все равно).

Подводя итог, вы обычно используете sleep() для синхронизации по времени и wait() для многопоточной синхронизации.

Они могли быть реализованы таким же образом в базовой ОС или не реализовываться вообще (поскольку в предыдущих версиях Java не было реальной многопоточности; вероятно, некоторые небольшие виртуальные машины этого тоже не делают). Не забывайте, что Java работает на виртуальной машине, поэтому ваш код будет преобразован во что-то другое в зависимости от виртуальной машины / OS / HW, на которой он выполняется.

java multithreading