Різниця між очікуванням () і сном ()


1203

Яка різниця між a wait()і sleep()Threads?

Чи я розумію, що wait()-ing Thread все ще знаходиться в запущеному режимі і використовує цикли процесора, але a sleep()-ing не споживає жодного циклу процесора?

Чому у нас є і те, wait() і іншеsleep() : як їх реалізація змінюється на нижчому рівні?


50
дуже гарне запитання. семантику обох легко сплутати.
Андреас Петерсон

1
Дуже приємні запитання, але вони 2 в одному. Чому у нас обоє - це не те саме, як вони можуть (а не є!) Реалізовані на нижчому рівні. Я відповів і на це.
estani

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

1
Ось хороша стаття, що описує її: qat.com/using-waitnotify-instead-thread-sleep-java
Чоловік Тритона

3
ВИКЛЮЧНО навпаки - сон "використовує" всі наявні CPU-цикли, але оскільки нитка буде знаходитись у "ОЧАКУВАННІ" - держава може бути отримана при необхідності - адже більшість операційних систем автоматично дають цикли, якщо це можливо, отже ваш потік не створить ніякого фактичного завантаження процесора ... він буде робити це в старих операційних системах. Object.wait (), з іншого боку, НІКОЛИ не використовує будь-яких циклів (не будучи невідомими), оскільки це реалізується через переривання програмного забезпечення в багатьох випадках - приватні, перехідні та прозорі блокування, реалізовані JVM. Thread.sleep - це погана практика.
спеціаліз

Відповіді:


837

А 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(); }
}

131
Ні, не може. Його можна перервати лише.
Петро Штібрані

9
Коли ви перебиваєтесь, ви повинні знати, яку нитку ви хочете перервати. Коли ви телефонуєте сповіщення, вам просто потрібен об'єкт, і вам не байдуже, чи є якийсь інший потік, який 'чекає' на цьому об’єкті. очікувати / повідомляти використовується для спілкування, а сон - для, ем, сну.
Петро Штібрані

28
@Geek - чому ти в світі кажеш чекати () витрачає цикли процесора?
Роберт Мунтяну

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

13
Я прочитав усі відповіді, проте все ще відчуваю трохи інформації, що не вистачає. Багато людей записували визначення з Javadoc, а також значення двох англійських слів, але я не бачу Чому я коли-небудь повинен використовувати сон, а не чекати? Яка порівняльна оцінка та різниця швидкостей між ними? Якщо я можу робити все, що можу робити зі сном, чому я повинен коли-небудь вибирати сон?
Balazs Zsoldos

334

Ще одна ключова відмінність, яка ще не згадується, полягає в тому, що під час сну Thread не звільняє замки, які вона тримає, а в очікуванні вимкне замок на об'єкт, який 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 , а питання про цитату "як змінюється їх реалізація на нижчому рівні?" цитувати.
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

243

Я вважаю цю публікацію корисною. Це ставить різницю між Thread.sleep(), Thread.yield()і Object.wait()в людському плані. Цитувати:

Все це врешті-решт пробивається до планувальника ОС, який видає часові часові відтворення на процеси та потоки.

sleep(n)каже: "Я закінчую з моїм часовим відрізком, і, будь ласка, не дайте мені ще один принаймні п мілісекунд". ОС навіть не намагається запланувати сплячу нитку, поки не пройде запитуваний час.

yield()каже: "Я закінчив з моїм часовим відрізком, але мені ще належить попрацювати". ОС вільна негайно надати потоку ще один часовий фрагмент або надати інший потік або обробити процесор, поступаючий потік щойно відмовився.

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

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

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


Вихід в основному залежить від платформи ... javamex.com/tutorials/threads/yield.shtml
Pacerier

Пояснення sleep(n)неявно говорить про те, що поточна поточна нитка добровільно відмовляється від монітора блокування, що не відповідає дійсності . Цитата з javadoc теми : "Нитка не втрачає права власності на жодні монітори".
Клінт Іствуд

2
@Jonathan у відповіді не згадується про монітори, і це тому, sleepщо не має особливої ​​поведінки щодо монітора, ніж будь-який інший виклик методу Java, тобто він не взаємодіє і не змінює їх жодним чином. Якщо ви щось скажете про монітори, вам слід вказати, що wait, крім вищезазначених речей, тимчасово відмовляться від блокування на об'єкт, на який він викликається.
pqnet

Як працює сповіщення на рівні планувальника ОС? Чи повідомляє виклик якогось обробника події з певним ідентифікатором потоку, дозволяючи планувальнику повернути відповідний потік назад у запущену чергу? Також у мене є ще одне питання, куди вписується концепція спінлок? Це буде актуально лише для сну або ж чекає, коли він використовує спінлок на дуже низькому рівні?
CMCDragonkai

@Erich, використовувати wait(n)для порівняння sleep(n). Немає сенсу порівнювати використання no-arg.
Pacerier

68

Тут є багато відповідей, але я не зміг знайти жодного смислового розрізнення.

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

sleep()відправляє Нитку спати, як це було раніше, вона просто запаковує контекст і припиняє виконувати заздалегідь визначений час. Тож для того, щоб прокинутись до встановленого часу, потрібно знати посилання на тему. Це не звичайна ситуація в багатопотоковому середовищі. Він здебільшого використовується для синхронізації часу (наприклад, пробудження рівно за 3,5 секунди) та / або жорсткого кодування справедливості (просто спати деякий час і нехай інші потоки працюють).

wait()навпаки, це механізм синхронізації потоку (або повідомлення), який дозволяє повідомляти Тему, про яку у вас немає збереженої посилання (ні догляду). Ви можете розглядати це як шаблон публікації-підписки ( wait== підписатися та notify()== опублікувати). В основному за допомогою notify () ви надсилаєте повідомлення (яке, можливо, взагалі не отримується, і, як правило, вам все одно).

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

Вони можуть бути реалізовані таким же чином і в базовій ОС, або взагалі (як і в попередніх версіях Java, не було справжньої багатопотокової редакції; напевно, деякі невеликі віртуальні машини теж не роблять цього). Не забувайте, що Java працює на VM, тому ваш код буде перетворений на щось інше відповідно до 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()може дзвонити з будь-якого місця. конкретної вимоги немає.

Ref: Різниця між режимом очікування та сну

Фрагмент коду для виклику методу очікування та сну

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

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

перехід потоку в різні стани потоку


Чи правильно, що спальну нитку можна розбудити дзвінками, щоб сповістити ()? Деякі з інших публікацій тут, схоже, означають, що сплячу нитку не можна прокинути, а перервати.
berimbolo

Так, Thread.sleep()використовується для надання часу процесора доступним для інших потоків. період сну може бути припинений перервами (тобто JVM). Прочитайте цю stackoverflow.com/questions/4264355 / ...
roottraveller

Цей пост також говорить, що переривання () - це те, що будить сплячу нитку? Я мав на увазі діаграму стану потоку, яку ви розмістили, де написано сповістити або notifyAll повернути сплячу (не чекаючу) нитку до готовності до запуску. Я просто хочу переконатися, що я це розумію.
berimbolo

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

2
Гаразд, мені потрібно прочитати більше про планування потоків, оскільки я не можу знайти приклади сповіщення () або notifyAll (), що пробуджуючі нитки лише переривають (), роблячи це. Усі приклади стосуються notify () та notifyAll () до потоків, які очікують на деякий об’єкт монітора.
berimbolo

29

Є кілька ключових зауважень різниці, які я закінчую після роботи в режимі очікування і сну, спочатку подивіться на зразок, використовуючи функцію wait () і сон ():

Приклад1 : використання wait () та сну ():

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 (): при синхронізованому багатопотоковому доступі до того ж Object (HandObject) (коли потрібна комунікація між більш ніж однією ниткою (кодування виконання потоку, виконання потоку отримати пиво) доступ до того самого об'єкта HandObject)
    • sleep (): під час очікування продовження виконання (очікування пива доступним)
  3. Утримуйте замок :
    • wait (): відпустіть замок для іншого об'єкта, має шанс виконати (HandObject безкоштовний, ви можете виконати іншу роботу)
    • sleep (): тримайте замок щонайменше t разів (або поки не перериваюсь) (Моя робота все ще не закінчується, я продовжую тримати замок і чекаю деякої умови, щоб продовжити)
  4. Умова пробудження :
    • wait (): до виклику notify (), notifyAll () від об'єкта
    • сон (): поки принаймні час не закінчиться або перервати дзвінок
  5. І останній пункт використовувати , коли в якості estani вказують:

ви зазвичай використовуєте сон () для синхронізації в часі і чекаєте () для багатопотокової синхронізації.

Будь ласка, виправте мене, якщо я помиляюся.


25

Різниця між очікуванням () і сном ()

  • Принципова відмінність полягає в тому, що 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 або кидок, щоб отримати доступ до цих методів.

Я сподіваюся, що це вам допоможе.


16

джерело: http://www.jguru.com/faq/view.jsp?EID=47127

Thread.sleep()відправляє поточний потік у стан "Не виконується" на деякий час. Потік зберігає монітори, якими він користувався - тобто, якщо нитка зараз знаходиться в синхронізованому блоці або методі, жоден інший потік не може ввести цей блок або метод. Якщо t.interrupt()викличе інша нитка, вона прокинеться сплячої ниткою.

Зауважте, що сон - це статичний метод, який означає, що він завжди впливає на поточну нитку (ту, що виконує метод сну). Поширена помилка - називати, t.sleep()де t - інша нитка; навіть тоді спляча поточна нитка, а не нитка t.

t.suspend()застаріло. За допомогою нього можна зупинити нитку, відмінну від поточної. Підвісна різьба тримає всі свої монітори, і оскільки цей стан не переривається, він схильний до тупикової ситуації.

object.wait()посилає поточну нитку в стан "Не виконується" , як sleep(), але з поворотом. Чекання викликається на об'єкті, а не на потоці; ми називаємо цей об’єкт "об'єктом блокування". Перш ніж lock.wait()викликати, поточний потік повинен синхронізуватися на об'єкті блокування; wait() потім звільняє цей замок і додає нитку до "списку очікування", пов'язаного з блокуванням. Пізніше інший потік може синхронізуватися на тому самому об'єкті блокування та викликати lock.notify(). Це прокидає оригінальну, чекаючу нитку. В основному, wait()/ notify()є як sleep()/ interrupt(), тільки активний потік не потребує прямого вказівника на сплячу нитку, а лише на спільний об'єкт блокування.


14

Чекати і спати - це дві різні речі:

  • У sleep()потоці перестає працювати протягом зазначеної тривалості.
  • У wait()потоці перестає працювати, поки об'єкт, який чекає, не буде повідомлено, як правило, іншими потоками.

але ви можете перервати сплячу Нитку. У цьому випадку wait () є надмірною дією, він також витрачає цикли процесора :-(
Geek,

9
Зачекайте, що не витрачаються цикли процесора.
Петро Штібрані

1
@Peter - я думаю, що так і є. Він чекає () на свою частину циклів процесора, а потім ОС передає цикли процесора іншим потокам. Я думаю, що це може залежати від ОС, я не впевнений.
Geek

3
Було б дуже погано реалізувати функцію wait (), якби вона витрачала цикли процесора. зачекати / сповістити використовується досить багато для межпотокового спілкування.
Петро Штібрані

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

11

sleepє методом Thread, waitє методом Object, так wait/notifyсамо є технікою синхронізації спільних даних на Java (за допомогою монітора ), але sleepце простий метод потоку, щоб призупинити себе.


8

sleep () - це метод, який використовується для того, щоб затримати процес протягом декількох секунд або потрібного часу, але у випадку, якщо потік () потік методу переходить у стан очікування, і він не повернеться автоматично, поки ми не зателефонуємо сповістити () або notifyAll ().

Основна відмінність в тому , що очікування () звільняє блокування або монітор під час сну () не звільняє будь-який замок або монітор під час очікування. Зачекання використовується для зв'язку між потоками, тоді як сон використовується, як правило, для введення пауз при виконанні.

Thread.sleep () пересилає поточний потік у стан "Не виконується" на деякий час. Потік зберігає придбані монітори - тобто, якщо нитка зараз знаходиться в синхронізованому блоці чи методі, жоден інший потік не може ввести цей блок або метод. Якщо інша нитка викликає t.interrupt (), вона прокинеться спальної нитки. Зауважте, що сон - це статичний метод, який означає, що він завжди впливає на поточну нитку (ту, що виконує метод сну). Поширена помилка - викликати t.sleep (), де t - інша нитка; навіть тоді спляча поточна нитка, а не нитка t.

object.wait () пересилає поточну нитку в стан "Not Runnable", як сон (), але з поворотом. Чекання викликається на об'єкті, а не на потоці; ми називаємо цей об’єкт "об'єктом блокування". Перед тим, як викликати 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 (): Дзвінок на об'єкт; поточний потік повинен синхронізуватися на об'єкті блокування.
  • сон (): дзвоніть на нитку; завжди виконує нитку.

Synchronized:

  • wait (): коли синхронізовані кілька потоків отримують доступ до одного Об'єкта один за одним.
  • sleep (): при синхронізації декількох потоків чекайте сну над сплячою ниткою.

Hold lock:

  • wait (): відпустіть замок для інших об'єктів, щоб мати шанс виконати.
  • sleep (): тримайте замок щонайменше t разів, якщо вказано тайм-аут або хтось перерве.

Wake-up condition:

  • wait (): до виклику notify (), notifyAll () від об'єкта
  • сон (): поки щонайменше не закінчиться час або перервати виклик ().

Usage:

  • сон (): для синхронізації часу і;
  • wait (): для багатопотокової синхронізації.

Ref: диференціал sleepіwait


6

Простими словами, чекати - чекати, поки якийсь інший потік не викликає вас, тоді як сон "не виконує наступне твердження" протягом певного визначеного періоду часу.

Крім того, сон є статичним методом у класі Thread, і він працює на потоці, тоді як wait () знаходиться в класі Object і викликається об'єктом.

Ще один момент, коли ви закликаєте чекати на якомусь об'єкті, нитка, що займається, синхронізує об'єкт і потім чекає. :)


1
Навіщо тобі обоє? Чому сон () недостатній?
Geek

2
Повідомлення використовується для зв'язку між потоками. Щоб зателефонувати зачекати, вам потрібен якийсь об’єкт, синхронізуйте його, а потім дзвінок зачекайте на ньому. Щоб отримувати сповіщення, вам потрібно інший потік для синхронізації на одному об’єкті та сповіщення про дзвінки.
Петро Штібрані

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) Потік повертає замок після того, як інші потоки викликають або сповіщення (), або notifyAll () способи того ж блокування.

3) метод wait () повинен бути викликаний у синхронізованому блоці.

4) метод wait () завжди викликається на об'єктах.

5) Нитки очікування можуть бути пробуджені іншими потоками за допомогою виклику методів notify () або notifyAll ().

6) Для виклику методу wait () потік повинен мати блокування об'єкта.

сон () Метод

1) Потік, який викликає метод sleep (), не звільняє блокування, яке він тримає.

2) метод сну () може бути викликаний всередині або поза синхронізованим блоком.

3) метод сну () завжди викликається на нитках.

4) Сплячі нитки не можуть бути пробуджені іншими нитками. Якщо це зроблено, нитка викине InterruptedException.

5) Для виклику методу sleep () потоці не потрібно мати блокування об'єктів.


4
  1. wait()це метод Objectзаняття.
    sleep()це метод Threadзаняття.

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

  3. wait()дозволяє потоку звільнити замок і goes to suspended state.
    Цей потік буде активним, коли виклик a notify()або notifAll()методу для одного і того ж об'єкта.


4

Одна з потенційних великих різниць між сном / перериванням та очікуванням / сповіщенням полягає в тому, що

Створення винятку, коли це не потрібно, є неефективним. Якщо у вас є потоки, що спілкуються один з одним з високою швидкістю, то це створило б багато винятків, якби ви весь час викликали переривання, що є загальною тратою процесора.


+1, насправді дійсна точка, хоча, сперечаючись на внутрішніх умовах реалізації, може бути більш доречною для аналізу продуктивності ...
Pacerier

Іншими словами, накладні витрати на створення виключень можуть бути значно меншими, ніж накладні витрати на реалізацію системи один проти іншого.
Pacerier

3

Ви маєте рацію - функція Sleep () спричиняє, що цей потік "спає", і процесор відключиться і обробить інші потоки (інакше відомі як контекстна комутація).

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

Також зауважте, що сон примушує переключення контексту.

Також - взагалі неможливо керувати комутацією контексту - під час очікування операційна система може (і буде довше чекати) обробляти інші потоки.


4
wait () не підтримує процесор, що обробляє поточний потік. Це як сон у тому, що він викликає і переключення контексту: javamex.com/tutorials/threads/context_switch.shtml . Я просив півроку все навколо stackoverflow і, здається, ніхто не знає, в чому різниця між очікувати / сповіщати проти сну / переривати.
Pacerier

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

@VladimirNabokov, Зовнішній тригер є interrupt. Час закінчення знаходиться nв wait(n). ¶¶ Вже 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, er, sleepале тоді вам доведеться турбуватися про блокування.

Жоден із методів не використовує процесор під час сну / очікування.

Методи реалізуються за допомогою власного коду, використовуючи подібні конструкції, але не однаково.

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


Thread.sleep також може бути встановлено на невизначений час. Терміни Object.wait також можуть бути встановлені на визначене. Ця відповідь не пояснює, чому нам потрібні два молотки, які роблять те саме.
Pacerier

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

3

Тут wait () буде в стані очікування, поки не сповістить іншу нитку, але де, як сон () буде мати деякий час .. після цього він автоматично перейде в стан Ready ...


3

Зачекати () та поспати () відмінності?

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 секунд і трапляється перерваний виняток ????
Geek

@Geek An InterruptedExceptionкидається, як це написано в Javadoc.
користувач207421

@EJP: Ви той самий EJP, який був на форумах sun.java.com? Принаймні ваш рахунок підказує те саме :-)
Geek

2

sleep()метод змушує поточний потік переходити з запущеного стану в стан блокування протягом певного часу. Якщо поточний потік має блокування будь-якого об'єкта, він продовжує його утримувати, це означає, що інші потоки не можуть виконати жодного синхронізованого методу в цьому об'єкті класу.

wait() метод змушує поточний потік переходити в стан блоку або протягом визначеного часу, або до повідомлення, але в цьому випадку потік звільняє блокування об'єкта (це означає, що інші потоки можуть виконувати будь-які синхронізовані методи виклику об'єкта.


2

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

Чому очікування / повідомлення є більш підходящим? Ось деякі особисті міркування:

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

  2. Він примушує синхронізацію. Оскільки він змушує програміста завершити виклик, щоб чекати / повідомляти в синхронізованому блоці.

  3. Це не залежно від походження та кількості нитки. При такому підході ви можете додавати більше потоків довільно, не редагуючи інші потоки та не відслідковуючи існуючі. Якщо ви використовували сон / переривання, спочатку вам потрібно буде зберегти посилання на сплячі нитки, а потім перервати їх по черзі вручну.

Приклад із реального життя, який добре пояснити це, - це класичний ресторан та метод, який персонал використовує для спілкування між ними: офіціанти залишають запити клієнтів у центральному місці (пробкова дошка, стіл тощо), дзвонить у дзвін, і робітники з кухні приходять приймати такі прохання. Після того, як будь-який курс готовий, персонал кухні знову дзвонить у дзвіночок, щоб офіціанти знали і приймали їх до клієнтів.


2

Приклад про сон не вимикає блокування і очікування робить

Тут є два класи:

  1. Основне : Містить основний метод та дві нитки.
  2. Синглтон : Це однотонний клас з двома статичними методами 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 чекає назовні, поки потік не відпустить його блокування.

Тепер змінити Singleton.java, коментуючи Thread.sleep (500); метод і не коментуючи Singleton.class.wait (500); . Тут через Singleton.class.wait (500); метод threadA звільнить усі придбані блокування і перейде в стан "Не запускається", 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, НЕ однакові, оскільки ниткаB отримала зміну для введення в синхронізований блок і через 500 мілісекунд ниткаA запустилася з останнього положення і створила ще один об'єкт 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

З сторінки документації oracle на метод wait ()Object :

public final void wait()
  1. Змушує поточний потік чекати, поки інший потік викликає notify()метод або notifyAll()метод для цього об’єкта. Іншими словами, цей метод поводиться точно так, ніби він просто виконує дзвінок wait(0).
  2. Поточний потік повинен володіти монітором цього об’єкта. Потік звільняє право власності на цей монітор і чекає, поки інший потік сповістить потоки, які чекають на моніторі цього об'єкта, щоб прокинутися
  3. можливі перебої та помилкові пробудження
  4. Цей метод повинен викликатися лише потоком, який є власником монітора цього об'єкта

Цей метод кидає

  1. IllegalMonitorStateException - якщо поточний потік не є власником монітора об'єкта.

  2. InterruptedException- якщо якась нитка перервала поточну нитку до або під час поточної нитки чекала на сповіщення. Перерваний статус поточного потоку очищається при скиданні цього винятку.

З сторінки документації Oracle про метод класу 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блоку або методу. Відповідь нічого не пояснює.
користувач207421

1
  • Метод wait(1000)змушує поточну нитку спати до однієї секунди .
    • Нитка може спати менше 1 секунди, якщо вона отримує виклик notify()абоnotifyAll() метод.
  • Виклик sleep(1000)змушує спливати поточну нитку рівно 1 секунду .
    • Також спляча нитка не містить блокування жодного ресурсу . Але чекає нитка.

1
sleep(1000)не гарантує спати рівно 1 секунду. Він може бути перерваний раніше.
Луціо

1
Ці пости настільки заплутані. Усі інші публікації в цій нитці говорять про те, що спляча нитка НЕ ​​утримує замок і що очікувана нитка НЕ ​​тримає замок. Аналогічно, пост із діаграмою передбачає, що виклики сповіщати () пробудити сплячі потоки, але інші повідомлення (та діаграми стану потоку) означають, що це роблять лише переривання () або проходження періоду очікування. Я просто замовив собі на практиці копію java concurrency, щось, що я повинен був прочитати давно!
berimbolo

1

Насправді все це чітко описано в документах Java (але я зрозумів це лише після прочитання відповідей).

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

wait () - Поточний потік повинен мати монітор цього об'єкта. Потік звільняє право власності на цей монітор і чекає, поки інший потік сповістить потоки, які чекають на моніторі цього об’єкта, або через виклик методу сповіщення або метод notifyAll. Потім потік чекає, поки він зможе знову отримати право власності на монітор і відновити виконання.

sleep () - примушує поточний виконуваний потік спати (тимчасово припиняє виконання) протягом вказаної кількості мілісекунд, за умови точності та точності системних таймерів та планувальників. Нитка не втрачає права власності на жодні монітори.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.