Разница между ожиданиями () и сном () - PullRequest
1128 голосов
/ 24 июня 2009

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

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

Почему у нас есть и wait(), и sleep(): как их реализация меняется на более низком уровне?

Ответы [ 32 ]

792 голосов
/ 24 июня 2009

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

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

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

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

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

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

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

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

synchronized {
    while (!condition) { mon.wait(); }
}
315 голосов
/ 24 июня 2009

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

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


synchronized(LOCK) {
    LOCK.wait(); // LOCK is not held
}
224 голосов
/ 05 августа 2011

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

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

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

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

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

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

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

65 голосов
/ 19 апреля 2012

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

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

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

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

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

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

49 голосов
/ 28 декабря 2015

Здесь я перечислил несколько важных различий между wait() и sleep() методами.
PS: Также нажмите на ссылки, чтобы увидеть код библиотеки (внутренняя работа, просто поиграйте немного для лучшего понимания).

ожидание ()

  1. wait() метод снимает блокировку.
  2. wait() - это метод Object класса.
  3. wait() - нестатический метод - public final void wait() throws InterruptedException { //...}
  4. wait() следует уведомить notify() или notifyAll() методами.
  5. wait() метод должен вызываться из цикла, чтобы справиться с ложной тревогой.

  6. wait() метод должен быть вызван из синхронизированного контекста (то есть синхронизированного метода или блока), в противном случае он выдаст IllegalMonitorStateException

сон ()

  1. sleep() метод не снимает блокировку.
  2. sleep() - метод класса java.lang.Thread.
  3. sleep() - статический метод - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
  4. по истечении указанного промежутка времени, sleep() завершено.
  5. sleep() лучше не звонить из цикла (т. Е. см. Код ниже ).
  6. sleep() можно вызывать откуда угодно. нет конкретных требований.

Ссылка: Разница между ожиданием и сном

Фрагмент кода для вызова метода ожидания и сна

synchronized(monitor){
    while(condition == true){ 
        monitor.wait()  //releases monitor lock
    }

    Thread.sleep(100); //puts current thread on Sleep    
}

thread transition to different thread states

28 голосов
/ 19 мая 2012

Существуют некоторые заметки о ключевых отличиях, которые я заключаю после работы над ожиданием и сном. Сначала рассмотрим пример, используя wait () и sleep ():

Example1 : с использованием wait () и sleep ():

synchronized(HandObject) {
    while(isHandFree() == false) {
        /* Hand is still busy on happy coding or something else, please wait */
        HandObject.wait();
    }
}

/* Get lock ^^, It is my turn, take a cup beer now */
while (beerIsAvailable() == false) {
    /* Beer is still coming, not available, Hand still hold glass to get beer,
       don't release hand to perform other task */
    Thread.sleep(5000);
}

/* Enjoy my beer now ^^ */
drinkBeers();

/* I have drink enough, now hand can continue with other task: continue coding */
setHandFreeState(true);
synchronized(HandObject) {
    HandObject.notifyAll();
}

Давайте уточним некоторые ключевые примечания:

  1. Звоните :
    • wait (): вызов текущего потока, который содержит объект HandObject
    • sleep (): вызов выполнения задачи Thread для получения пива (это метод класса, влияющий на текущий запущенный поток)
  2. Синхронное :
    • wait (): при синхронизированном многопоточном доступе к одному и тому же объекту (HandObject) (когда требуется связь между несколькими потоками (поток выполняет кодирование, поток выполняет get beer) доступ к одному и тому же объекту HandObject)
    • sleep (): при выполнении условия ожидания для продолжения (ожидание пива доступно)
  3. Блокировка удержания :
    • wait (): снять блокировку для другого объекта, который может быть выполнен (HandObject свободен, вы можете выполнять другую работу)
    • sleep (): удерживать блокировку не менее t раз (или до прерывания) (моя работа все еще не завершена, я продолжаю удерживать блокировку и ожидаю продолжения некоторого условия)
  4. Состояние пробуждения :
    • wait (): до вызова notify (), notifyAll () из объекта
    • sleep (): по крайней мере до истечения времени или прерывания вызова
  5. И последняя точка используется, когда как estani указывает:

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

Пожалуйста, поправьте меня, если я ошибаюсь.

22 голосов
/ 24 июля 2015

Разница между ожиданиями () и сном ()

  • Принципиальное отличие состоит в том, что wait() от Object, а sleep() - статический метод Thread.

  • Основное отличие состоит в том, что wait() снимает блокировку, а sleep() не снимает блокировку во время ожидания.

  • wait() используется для связи между потоками, в то время как sleep() используется, как правило, для приостановки выполнения.

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

  • Чтобы снова начать поток с wait(), вам нужно позвонить notify() или notifyAll(). Что касается sleep(),, поток запускается через указанный интервал времени.

Сходство

  • В обоих случаях текущий поток переходит в состояние Not Runnable .
  • Оба являются родными методами.
18 голосов
/ 19 апреля 2012

Это очень простой вопрос, потому что оба эти метода имеют совершенно разное использование.

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

Это было просто ясное и простое объяснение, если вы хотите большего, тогда продолжайте чтение.

В случае wait() поток метода переходит в состояние ожидания и не возвращается автоматически, пока мы не вызовем метод notify() (или notifyAll(), если у вас более одного потока в состоянии ожидания и вы хотите разбудить все эти темы). А для доступа к методам wait() или notify() или notifyAll() вам нужно синхронизировать объект или получить блокировку объекта или класса. И еще одна вещь, метод wait() используется для связи между потоками, потому что, если поток переходит в состояние ожидания, вам понадобится другой поток, чтобы разбудить этот поток.

Но в случае sleep() это метод, который используется для удержания процесса в течение нескольких секунд или нужного времени. Потому что вам не нужно провоцировать какой-либо метод notify() или notifyAll(), чтобы вернуть этот поток. Или вам не нужен какой-либо другой поток, чтобы перезвонить этому потоку. Например, если вы хотите, чтобы что-то произошло через несколько секунд, как в игре после поворота пользователя, вы хотите, чтобы пользователь ждал, пока компьютер начнет играть, вы можете упомянуть метод sleep().

И еще одно важное отличие, которое часто задают в интервью: sleep() относится к Thread классу и wait() относится к Object классу.

Это все различия между sleep() и wait().

И у обоих методов есть сходство: оба они являются проверенным оператором, поэтому вам нужно попробовать catch или throws для доступа к этим методам.

Надеюсь, это поможет вам.

16 голосов
/ 05 ноября 2011

источник: http://www.jguru.com/faq/view.jsp?EID=47127

Thread.sleep() отправляет текущий поток в состояние "Not Runnable" в течение некоторого времени. Нить хранит мониторы, которые она приобрела - т.е. если поток в настоящее время находится в синхронизированном блоке или методе, никакой другой поток не может войти в этот блок или метод. Если другой поток вызывает t.interrupt(), он пробуждает спящий поток.

Обратите внимание, что сон является статическим методом, что означает, что он всегда влияет текущий поток (тот, который выполняет метод сна). Распространенной ошибкой является вызов t.sleep(), где t - другой поток; даже тогда будет текущий поток, а не поток t.

t.suspend() устарело. Используя можно остановить поток другой чем текущий поток. Подвешенная нить держит все свои мониторы и поскольку это состояние не является прерываемым, оно склонно к тупику.

object.wait() отправляет текущий поток в состояние "Not Runnable" , как sleep(), но с изюминкой. Ожидание вызывается для объекта, а не нить; мы называем этот объект «объект блокировки». До того, как lock.wait() вызывается, текущий поток должен синхронизироваться на объекте блокировки; wait() затем снимает эту блокировку и добавляет поток в «список ожидания» связано с замком. Позже другой поток может синхронизироваться на тот же объект блокировки и вызов lock.notify(). Это пробуждает оригинал, жду нить. В основном, wait() / notify() это как sleep() / interrupt(), только активная нить не нуждается в прямой указатель на спящий поток, но только на объект общей блокировки.

14 голосов
/ 24 июня 2009

Ждать и спать две разные вещи:

  • В sleep() поток перестает работать на указанную продолжительность.
  • В wait() поток перестает работать, пока ожидаемый объект не будет уведомлен, как правило, другими потоками.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...