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


1204

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

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

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


50
очень хороший вопрос семантику обоих легко спутать.
Андреас Петерссон

1
Очень хорошие вопросы, но они 2 в одном. Почему у нас оба не такие, как они могут (и не являются!) Реализованы на более низком уровне. Я тоже ответил на это.
Эстани

Предположим, что поток A находится в синхронизированном блоке, и в то время как он находится в процессоре из этого потока, он взят и передан другому потоку B. Теперь, в котором состояние A перейдет, будут ли другие потоки, ожидающие в этом синхронизированном блоке, сейчас войти внутрь ?
Питер

1
Вот хорошая статья, описывающая это: qat.com/using-waitnotify-instead-thread-sleep-java
Triton Man,

3
СОВЕРШЕННО наоборот - режим сна "использует" все доступные циклы ЦП, но поскольку поток будет находиться в состоянии "ОЖИДАНИЕ", они могут быть получены в случае необходимости - фактически большинство операционных систем автоматически выдают циклы, ЕСЛИ это возможно, следовательно, ваш поток не будет создавать фактическую нагрузку на процессор ... он будет делать это на старых операционных системах. Object.wait (), с другой стороны, НИКОГДА не использует какие-либо циклы (будучи незамеченными), потому что они реализуются через программные прерывания во многих случаях - частные, временные и прозрачные блокировки, реализованные JVM. Thread.sleep - плохая практика.
специалист

Ответы:


838

A waitможет быть "разбужен" другим потоком, вызывающим notifyмонитор, которого ожидают, тогда как a 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(); }
}

131
Нет, не может. Это может быть только прервано.
Питер Штибраны

9
Когда вы прерываете, вы должны знать, какой поток вы хотите прервать. Когда вы вызываете notify, вам просто нужен объект, и вам все равно, есть ли какой-либо другой поток, который «ждет» этого объекта. ожидание / уведомление используется для связи, в то время как сон используется, например, для сна.
Питер Штибраны

28
@ Geek - почему в мире вы говорите, что wait () тратит время процессора?
Роберт Мунтяну

25
Прерывание предназначено как механизм, который мягко побуждает поток полностью прекратить работу и отменяет оставшиеся операции. wait/ notifyобычно используются для ожидания выполнения задачи другим потоком или для ожидания выполнения определенного условия.
Луи Вассерман

13
Я прочитал все ответы, однако я все еще чувствую немного недостающей информации. Многие люди записали определения из Javadoc, а также значение двух английских слов, но я не понимаю, почему я должен когда-либо использовать сон вместо ожидания? Какая разница в скорости между двумя тестами? Если я могу делать все, что я могу делать со сном, почему я должен когда-либо выбирать сон?
Balazs Zsoldos

334

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

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


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

105
Ожидание только снимает блокировку для объекта, для которого вы вызываете wait (). Это не освобождает никаких других замков.
Джон Скит

16
На самом деле вам не нужно вызывать сон изнутри блокировки - блокировки и ожидание / уведомление идут рука об руку, но блокировки и сон не связаны.
oxbow_lakes

7
@oxbow_lakes - Я бы сказал, что не стоит спать с замками, для этого есть несколько вариантов использования. Просто хотел указать на различия.
Роберт Мунтяну

5
@RobertMunteanu, Ваш ответ вводит в заблуждение, утверждая, что sleepсодержит блокировки Java , но это не так. Для того, чтобы иметь сравнение справедливой, мы бы сравнить synchronized(OUTER_LOCK){ Thread.sleep(1000); }с synchronized(OUTER_LOCK){ synchronized(LOCK){LOCK.wait();} }и мы можем видеть , что обе команды не отпустить OUTER_LOCK. Если есть какая-то разница, мы можем сказать, что в sleepявном виде не используются блокировки Java , но возникает вопрос о цитате "как их реализация меняется на более низком уровне?" Unquote.
Pacerier

2
@Pacerier wait()связан с состоянием самой внутренней блокировки, из которой он вызывается , в вашем примере кода wait()может только освобождаться, LOCKа не OUTER_LOCK. Вот как все-таки создан Java-монитор. Справедливое сравнение было бы synchronized(OUTER_LOCK){ synchronized(LOCK) { Thread.sleep(1000); } }и synchronized(OUTER_LOCK){ synchronized(LOCK) { LOCK.wait(); } }. В этом случае sleep()будет держать оба замка , пока wait()выпустят , LOCKно по- прежнему держатьOUTER_LOCK
Danze

244

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

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

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

yield()говорит: «Я закончил с моим расписанием, но у меня еще есть над чем работать». ОС может немедленно предоставить потоку другой временной интервал, или дать другому потоку или обработать ЦП, из которого уступил только исходящий поток.

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

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

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


Доходность в основном зависит от платформы ... javamex.com/tutorials/threads/yield.shtml
Pacerier

объяснение sleep(n)косвенно говорит о том, что текущий запущенный поток добровольно освобождает монитор блокировки, что не соответствует действительности . Цитата из ветки Javadoc : «Нить не теряет право собственности ни на какие мониторы».
Клинт Иствуд

2
@ Джонатан, в ответе нет упоминания о мониторах, и это потому, что sleepон не имеет никакого особого поведения в отношении монитора, чем любой другой вызов метода Java, то есть он не взаимодействует и не изменяет их каким-либо образом. Если вы хотите что-то сказать о мониторах, вы должны указать, что waitв дополнение к вышеперечисленным вещам временно снимет блокировку с вызываемого объекта.
pqnet

Как работает уведомление на уровне планировщика ОС? Вызывает ли notify какой-либо обработчик событий с определенным идентификатором потока, позволяющий планировщику вернуть соответствующий поток обратно в текущую очередь? Также у меня есть еще один вопрос, куда вписывается концепция спин-блокировки? Будет ли это актуально только для сна, или же само ожидание использует спинлок на очень низком уровне?
CMCDragonkai

@Erich, используйте wait(n)для сравнения sleep(n). Нет смысла сравнивать использование без аргументов.
Pacerier

68

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

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

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

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

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

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


54

Здесь я перечислил несколько важных различий между 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()может быть вызван откуда угодно. нет конкретных требований.

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

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

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

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

переход потока в разные состояния потока


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

Да, Thread.sleep()используется для предоставления процессорного времени доступным другим потокам. период ожидания может быть прерван прерываниями (т. е. JVM). Прочитайте это stackoverflow.com/questions/4264355/…
roottraveller

В этом посте также говорится, что interrupt () - это то, что пробуждает спящий поток? Я имел в виду диаграмму состояния потока, которую вы опубликовали, где написано «уведомить» или «уведомить». Все данные возвращают спящий (не ожидающий) поток к готовности к работе. Я просто хочу убедиться, что понимаю это.
беримболо

@berimbolo notify()или notifyAll()являются Objectметодами класса. следовательно, они доступны для всех классов (т. е. и для Threadклассов). см. код grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
roottraveller

2
Хорошо, мне нужно больше узнать о планировании потоков, так как я не могу найти примеры, когда notify () или notifyAll () пробуждают спящие потоки, только interrupt (), делающие это. Все примеры связывают notify () и notifyAll () с потоками, ожидающими некоторый объект монитора.
беримболо

29

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

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

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

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


26

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

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

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

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

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

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

сходства

  • Обе заставляют текущий поток перейти в Not Runnable .
  • Оба являются родными методами.

18

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

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

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

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

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

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

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

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

Я надеюсь, что это поможет вам.


16

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

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

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

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

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


14

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

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

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

9
Ожидание не тратит циклы процессора.
Питер Штибраны

1
@ Питер - я думаю, что так и есть. Он ждет () для своей части циклов ЦП, а затем ОС передает циклы ЦП другим потокам. Я думаю, что это может зависеть от ОС, я не уверен.
Компьютерщик

3
Реализация wait () была бы очень плохой, если бы она теряла циклы процессора. wait / notify довольно часто используется для межпотокового общения.
Питер Штибраны

2
@Pacerier две конструкции предназначены для разных целей. Если вы хотите, чтобы поток останавливался в течение фиксированного периода времени, который вы используете sleep, если вы хотите, чтобы он остановился, пока какой-то вход не поступит от другого, который вы используете wait/ notify. interruptпредназначено как способ сообщить потоку, что он должен прекратить делать то, что он делает, и завершиться. Он обрабатывается sleep, waitно также блокирует функции ввода / вывода (и вы можете реализовать функции с таким же поведением, вызвав метод Thread.interrupted()). Что касается производительности, функции обычно оптимизируются в соответствии с целью, для которой они были разработаны.
pqnet

11

sleepЭто метод Thread, waitметод Object, так wait/notifyже как и метод синхронизации общих данных в Java (с использованием монитора ), но sleepэто простой метод потоковой приостановки самого себя.


8

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

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

Thread.sleep () отправляет текущий поток в состояние «Not Runnable» на некоторое время. Поток хранит полученные им мониторы, т. Е. Если поток находится в синхронизированном блоке или методе, никакой другой поток не может войти в этот блок или метод. Если другой поток вызывает t.interrupt (), он разбудит спящий поток. Обратите внимание, что sleep - это статический метод, который означает, что он всегда влияет на текущий поток (тот, который выполняет метод sleep). Распространенной ошибкой является вызов t.sleep (), где t - другой поток; даже тогда будет текущий поток, а не поток.

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

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

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

Позвольте классифицировать все вышеперечисленные пункты:

Call on:

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

Synchronized:

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

Hold lock:

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

Wake-up condition:

  • wait (): до вызова notify (), notifyAll () из объекта
  • sleep (): пока не истечет хотя бы время или вызов interrupt ().

Usage:

  • sleep (): для синхронизации времени и;
  • wait (): для многопоточной синхронизации.

Ref: diff sleepиwait


6

Проще говоря, wait is wait До тех пор, пока какой-то другой поток не вызовет вас, тогда как sleep «не выполняет следующую инструкцию» в течение определенного периода времени.

Кроме того, sleep является статическим методом в классе Thread и работает с потоком, тогда как wait () находится в классе Object и вызывается для объекта.

Другой момент, когда вы вызываете wait для какого-либо объекта, вовлеченный поток синхронизирует объект и затем ожидает. :)


1
Зачем вам оба? Почему sleep () недостаточно?
Компьютерщик

2
Уведомление используется для связи между потоками. Чтобы вызвать wait, вам нужен какой-то объект, синхронизировать его, а затем вызвать wait на нем. Чтобы получить уведомление, вам нужен другой поток для синхронизации с тем же объектом и вызова notify.
Питер Штибраны

6

waitи sleepметоды очень разные:

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

Если подумать, имена сбивают с толку в этом отношении; однако sleepэто стандартное имя и waitпохоже на WaitForSingleObjectили WaitForMultipleObjectsв Win API.


3
Но мы можем прервать сон, не так ли? так в чем же разница с этим сном / прерыванием против ожидания / уведомления?
Pacerier

2
Вы можете прервать спящего человека, но можете уведомить только ожидающего. Темы одинаковые.
Риши

5

Из этого поста: http://javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/

Метод wait ().

1) Поток, который вызывает метод wait (), снимает блокировку, которую он удерживает.

2) Поток восстанавливает блокировку после того, как другие потоки вызывают методы notify () или notifyAll () для той же блокировки.

3) метод wait () должен быть вызван в синхронизированном блоке.

4) метод wait () всегда вызывается для объектов.

5) Ожидающие потоки могут быть разбужены другими потоками путем вызова методов notify () или notifyAll ().

6) Для вызова метода wait () поток должен иметь блокировку объекта.

Метод сна ()

1) Поток, который вызывает метод sleep (), не снимает блокировку, которую он удерживает.

2) метод sleep () может быть вызван внутри или снаружи синхронизированного блока.

3) метод sleep () всегда вызывается в потоках.

4) Спящие нитки не могут быть разбужены другими нитями. Если это сделано, поток выдаст исключение InterruptedException.

5) Чтобы вызвать метод sleep (), поток не должен иметь объектную блокировку.


4

Здесь wait () будет находиться в состоянии ожидания до тех пор, пока не получит уведомление от другого потока, но когда у функции sleep () будет некоторое время ... после этого он автоматически перейдет в состояние готовности ...


4
  1. wait()это метод Objectкласса.
    sleep()это метод Threadкласса.

  2. sleep()позволяет потоку перейти в sleepсостояние в течение x миллисекунд.
    Когда поток переходит в состояние сна it doesn’t release the lock.

  3. wait()позволяет потоку снять блокировку и goes to suspended state.
    Этот поток будет активен при вызове метода notify()или notifAll()для того же объекта.


4

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

Создание исключения, когда оно не нужно, неэффективно. Если у вас есть потоки, взаимодействующие друг с другом с высокой скоростью, то вы бы генерировали много исключений, если бы вы все время вызывали прерывание, что является полной тратой процессорного времени.


+1, на самом деле
верный

Другими словами, накладные расходы на создание исключений могут быть значительно меньше, чем накладные расходы на реализацию системы одного против другого.
Pacerier

3

Вы правы - Sleep () приводит к тому, что поток «спит», и процессор отключается и обрабатывает другие потоки (иначе называемые переключением контекста), когда, я полагаю, Wait заставляет процессор обрабатывать текущий поток.

У нас есть и то и другое, потому что, хотя может показаться разумным позволить другим людям использовать процессор, пока вы его не используете, на самом деле существуют издержки на переключение контекста - в зависимости от того, как долго длится спящий режим, он может быть дороже в циклах процессора переключать потоки, чем просто заставить ваш поток ничего не делать в течение нескольких мс.

Также обратите внимание, что сон вызывает переключение контекста.

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


4
wait () не сохраняет процессор, обрабатывающий текущий поток. Это похоже на сон в том, что оно также вызывает переключение контекста: javamex.com/tutorials/threads/context_switch.shtml . Я просил пол года вокруг stackoverflow, и кажется, что никто не знает, в чем разница между wait / notify и sleep / interrupt.
Пейсер

хотя спящий режим не удерживает процессор в обработке текущего потока, я думаю, в любом случае это немного обременительно для ЦП, поскольку ЦП необходимо отслеживать момент, когда закончить спящий режим. У него нет такого внешнего триггера, как "notify" в ожидании. Нет?
Владимир Набоков

@VladimirNabokov, внешний триггер есть interrupt. Время окончания nв wait(n). 8 Прошло 8 лет, и до сих пор никто не имеет ответа!
Pacerier

3

Методы используются для разных вещей.

Thread.sleep(5000);   // Wait until the time has passed.

Object.wait();        // Wait until some other thread tells me to wake up.

Thread.sleep (n) может быть прерван, но Object.wait () должен быть уведомлен. Можно указать максимальное время ожидания: Object.wait(5000)так что можно было бы использовать waitего, sleepно тогда вам придется беспокоиться о блокировках.

Ни один из методов не использует процессор во время сна / ожидания.

Методы реализованы с использованием нативного кода, с использованием аналогичных конструкций, но не одинаковым образом.

Посмотрите сами: доступен ли исходный код нативных методов? Файл /src/share/vm/prims/jvm.cppявляется отправной точкой ...


Временная привязка Thread.sleep также может быть установлена ​​на неопределенное время. Время Object.wait также может быть установлено на определенный. Этот ответ не объясняет, почему нам нужны 2 молотка, которые делают то же самое.
Pacerier

Thread.sleep(big_num) должен быть прерван. Object.wait(small_num) можно уведомить.
Pacerier

3

Wait () и sleep () Различия?

Thread.sleep () После того, как его работа завершена, только снятие блокировки для всех. пока его никогда не откроет замок никому.

  Sleep() take the key, its never release the key to anyone, when its work completed then only its release then only take the key waiting stage threads.

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

Например:

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

Подождите(). когда вы подавлены и принимаете другое среднее значение, пока вы ждете, это ожидание

вы воспроизводите фильм или что-то в своей системе так же, как проигрыватель, вы не можете воспроизводить более одного видео одновременно, вот и все, когда вы закрываете и выбираете другой фильм или песню, означающее, что время ожидания


3

waitснимает блокировку и sleepне делает Поток в состоянии ожидания , имеет право на пробуждение , как только notifyили notifyAllназываются. Но в случае, sleepесли поток сохраняет блокировку, он будет иметь право только после окончания времени ожидания.


Так что, если поток спит в течение 10 секунд и происходит прерванное исключение ????
Компьютерщик

@ Гик Ан InterruptedExceptionброшен, как говорится в Javadoc.
Маркиз Лорн

@EJP: Вы тот же EJP, кто был на форумах sun.java.com? По крайней мере, ваш счет предполагает то же самое :-)
Компьютерщик

2

sleep()Метод заставляет текущий поток переходить из состояния выполнения в состояние блокировки в течение указанного времени. Если текущий поток имеет блокировку какого-либо объекта, он продолжает удерживать ее, что означает, что другие потоки не могут выполнить какой-либо синхронизированный метод в этом объекте класса.

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


2

На мой взгляд, основное различие между обоими механизмами заключается в том, что режим сна / прерывания является самым основным способом обработки потоков, тогда как ожидание / уведомление - это абстракция, предназначенная для упрощения взаимодействия между потоками. Это означает, что сон / прерывание может делать что угодно, но эту конкретную задачу сложнее выполнить.

Почему ждать / уведомлять больше подходит? Вот некоторые личные соображения:

  1. Это обеспечивает централизацию. Это позволяет координировать связь между группой потоков с одним общим объектом. Это значительно упрощает работу.

  2. Это обеспечивает синхронизацию. Потому что это заставляет программиста обернуть вызов для ожидания / уведомления в синхронизированном блоке.

  3. Это не зависит от происхождения и номера потока. При таком подходе вы можете добавлять дополнительные потоки произвольно, не редактируя другие потоки и не отслеживая существующие. Если вы использовали режим сна / прерывания, сначала вам нужно будет сохранить ссылки на спящие потоки, а затем прерывать их одну за другой вручную.

Пример из реальной жизни, который хорошо объяснить, это классический ресторан и метод, который персонал использует для общения между ними: официанты оставляют запросы клиентов в центральном месте (пробковая доска, стол и т. Д.), позвоните в звонок, и рабочие с кухни приходят, чтобы принять такие просьбы. Когда все готово, кухонный персонал снова звонит в колокольчик, чтобы официанты знали и доставляли их покупателям.


2

Пример сна не снимает блокировку, а ожидание делает

Здесь есть два класса:

  1. Main : содержит основной метод и два потока.
  2. Singleton : это одноэлементный класс с двумя статическими методами getInstance () и getInstance (логическое isWait).

    public class Main {
    
    private static Singleton singletonA = null;
    private static Singleton singletonB = null;
    
    public static void main(String[] args) throws InterruptedException {
    
    Thread threadA = new Thread() {
        @Override
        public void run() {
    
            singletonA = Singleton.getInstance(true);
    
        }
    };
    
    Thread threadB = new Thread() {
        @Override
        public void run() {
            singletonB = Singleton.getInstance();
    
            while (singletonA == null) {
                System.out.println("SingletonA still null");
            }
    
            if (singletonA == singletonB) {
                System.out.println("Both singleton are same");
            } else {
                System.out.println("Both singleton are not same");
            }
    
        }
    };
    
    threadA.start();
    threadB.start();
    
     }
    }

а также

public class Singleton {

    private static Singleton _instance;

    public static Singleton getInstance() {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null)
                _instance = new Singleton();
        }
    }
    return _instance;

}

public static Singleton getInstance(boolean isWait) {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null) {
                if (isWait) {
                    try {
                        // Singleton.class.wait(500);//Using wait
                        Thread.sleep(500);// Using Sleep
                        System.out.println("_instance :"
                                + String.valueOf(_instance));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                _instance = new Singleton();
            }
        }
    }
    return _instance;

 }
}

Теперь запустите этот пример, вы получите ниже вывод:

_instance :null
Both singleton are same

Здесь экземпляры Singleton, созданные threadA и threadB, одинаковы. Это означает, что threadB ожидает снаружи, пока threadA не снимет свою блокировку.

Теперь измените Singleton.java, комментируя Thread.sleep (500); метод и раскомментирование Singleton.class.wait (500); , Здесь из-за Singleton.class.wait (500); метод threadA снимет все блокировки получения и переместится в состояние «Runnable», а threadB получит изменение для входа в синхронизированный блок.

Теперь запустите снова:

SingletonA still null
SingletonA still null
SingletonA still null
_instance :com.omt.sleepwait.Singleton@10c042ab
SingletonA still null
SingletonA still null
SingletonA still null
Both singleton are not same

Здесь экземпляры Singleton, созданные threadA и threadB, НЕ одинаковы, потому что threadB получил изменение для входа в синхронизированный блок и после 500 миллисекунд threadA начал с своей последней позиции и создал еще один объект Singleton.


2

Должен вызываться из синхронизированного блока: wait() метод всегда вызывается из синхронизированного блока, т. Е. wait()Метод должен блокировать монитор объекта перед объектом, для которого он вызывается. Но sleep()метод может быть вызван извне синхронизированного блока, т.е.sleep() Метод не нуждается ни в каком объектном мониторе.

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

Принадлежит к какому классу: wait() метод принадлежит java.lang.Objectклассу, но sleep()метод принадлежит java.lang.Threadклассу.

Вызывается для объекта или потока: wait() метод вызывается для объектов, но sleep()метод вызывается для потоков, а не объектов.

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

При вызове из синхронизированного блока: при wait()вызове метода поток покидает объектную блокировку. Но sleep()метод при вызове из синхронизированного блока или потока метода не оставляет объектную блокировку.

Для получения дополнительной ссылки


вероятно, лучший URL ссылки, чем этот.
Дрю

2

Со страницы документации оракула о методе wait ()Object :

public final void wait()
  1. Заставляет текущий поток ждать, пока другой поток не вызовет notify()метод или notifyAll()метод для этого объекта. Другими словами, этот метод ведет себя точно так же, как если бы он просто выполнял вызов wait(0).
  2. Текущий поток должен иметь монитор этого объекта. Поток освобождает владельца этого монитора и ждет, пока другой поток не уведомит потоки, ждущие на мониторе этого объекта, чтобы проснуться
  3. возможны прерывания и ложные пробуждения
  4. Этот метод должен вызываться только потоком, который является владельцем монитора этого объекта

Этот метод бросает

  1. IllegalMonitorStateException - если текущий поток не является владельцем монитора объекта.

  2. InterruptedException- если какой-либо поток прервал текущий поток до или в то время, когда текущий поток ожидал уведомления. Прерванное состояние текущего потока очищается при возникновении этого исключения.

Со страницы документации оракула по методу sleep ()Thread класса:

public static void sleep(long millis)
  1. Заставляет текущий исполняемый поток в спящий режим (временно прекращать выполнение) на указанное количество миллисекунд, в зависимости от точности и точности системных таймеров и планировщиков.
  2. Поток не теряет права собственности ни на какие мониторы.

Этот метод бросает:

  1. IllegalArgumentException - если значение миллис является отрицательным

  2. InterruptedException- если какой-либо поток прервал текущий поток. Прерванное состояние текущего потока очищается при возникновении этого исключения.

Другое ключевое отличие:

wait()это нестатический метод (метод экземпляра) в отличие от статического метода sleep()(метод класса).


1

wait()дается внутри синхронизированного метода, тогда sleep()как дается внутри несинхронизированного метода, потому что wait()метод освобождает блокировку объекта, но sleep()или yield()освобождает lock().


sleep()может быть внутри synchronizedблока или метода. Ответ ничего не объясняет.
маркиз Лорн

1
  • Этот метод wait(1000)заставляет текущий поток спать до одной секунды .
    • Поток может спать менее 1 секунды, если он получает вызов метода notify()илиnotifyAll() .
  • При вызове sleep(1000)текущий поток спит ровно 1 секунду .
    • Также спящий поток не удерживает блокировку любого ресурса . Но ожидание потока делает.

1
sleep(1000)не гарантирует спать ровно 1 секунду. Это может быть прервано раньше.
Лусио

1
Эти посты так запутаны. Все остальные сообщения в этой теме говорят, что спящий поток удерживает блокировку и что ожидающий поток не удерживает блокировку. Точно так же сообщение с диаграммой подразумевает, что вызовы notify () пробуждают спящие потоки, но другие сообщения (и диаграммы состояний потоков) подразумевают, что это делает только interrupt () или время ожидания. Я просто заказал себе копию java-параллелизма на практике, что я должен был прочитать давным-давно!
беримболо

1

Собственно, все это четко описано в документации Java (но я понял это только после прочтения ответов).

http://docs.oracle.com/javase/8/docs/api/index.html :

wait () - текущему потоку должен принадлежать монитор этого объекта. Поток освобождает владельца этого монитора и ожидает, пока другой поток не уведомит потоки, ожидающие на мониторе этого объекта, чтобы он проснулся либо посредством вызова метода notify, либо метода notifyAll. Затем поток ожидает, пока не получит право собственности на монитор, и возобновит выполнение.

sleep () - Заставляет текущий выполняющийся поток спать (временно прекращать выполнение) на указанное количество миллисекунд, в зависимости от точности и точности системных таймеров и планировщиков. Поток не теряет права собственности ни на какие мониторы.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.