Różnica między funkcją wait () a sleep ()

1203

Jaka jest różnica między wait()a sleep()w wątkach?

Czy rozumiem, że wait()wątek -ing wciąż działa w trybie roboczym i używa cykli procesora, ale sleep()-ing nie zużywa żadnych cykli procesora?

Dlaczego mamy jedno wait() i drugiesleep() : w jaki sposób ich wdrożenie różni się na niższym poziomie?

Maniak
źródło
50
bardzo dobre pytanie. semantykę obu można łatwo pomylić.
Andreas Petersson
1
Bardzo fajne pytania, ale są dwa w jednym. Dlaczego mamy oba, to nie to samo, jak mogą (i nie są!) Zaimplementowane na niższym poziomie. Ja też na to odpowiedziałem.
estani
Załóżmy, że wątek A znajduje się w zsynchronizowanym bloku i gdy znajduje się w jednostce centralnej, ten wątek jest pobierany i przekazywany do innego wątku B, w którym teraz stanie się wątek A, czy pozostałe wątki oczekujące na tym zsynchronizowanym bloku wejdą teraz do środka ?
Peter,
1
Oto dobry artykuł opisujący to: qat.com/using-waitnotify-instead-thread-sleep-java
Triton Man
3
DOKŁADNIE przeciwnie - tryb uśpienia „wykorzystuje” wszystkie dostępne cykle procesora, ale ponieważ wątek będzie w stanie „OCZEKIWANIA” - można go uzyskać w razie potrzeby - w rzeczywistości większość systemów operacyjnych automatycznie generuje cykle, JEŚLI jest to możliwe, stąd twój wątek nie wytworzy żadnego rzeczywistego obciążenia procesora ... zrobi to jednak na starszych systemach operacyjnych. Z drugiej strony Object.wait () NIGDY nie używa żadnych cykli (nie będąc powiadomionymi), ponieważ są one realizowane przez przerwania programowe w wielu przypadkach - prywatne, przejściowe i przezroczyste blokady, implementowane przez JVM. Thread.sleep to zła praktyka.
specializt

Odpowiedzi:

837

A waitmoże zostać „obudzony” przez inny wątek wzywający notifymonitor, na który czeka się, podczas gdy sleepnie. Również wait(i notify) musi się zdarzyć w bloku synchronizedobiektu monitora, podczas sleepgdy nie:

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

W tym momencie aktualnie wykonywany wątek czeka i zwalnia monitor . Może zrobić inny wątek

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

(na tym samym monobiekcie) i pierwszy wątek (zakładając, że jest to jedyny wątek oczekujący na monitorze) się obudzi.

Możesz także zadzwonić, notifyAlljeśli więcej niż jeden wątek czeka na monitorze - to obudzi je wszystkie . Jednak tylko jeden wątek będzie w stanie chwycić monitor (pamiętaj, że waitjest w synchronizedbloku) i kontynuować - pozostałe zostaną zablokowane, dopóki nie uzyskają blokady monitora.

Inną kwestią jest to, że zadzwonisz waitna Objectsiebie (to znaczy czekać na monitorze obiekt za), natomiast zadzwonić sleepna Thread.

Jeszcze innym jest to, że można dostać fałszywych wybudzeń z wait(tj wątku czeka CV bez wyraźnego powodu). Powinieneś zawsze waitpodczas przędzenia na jakimś stanie w sposób następujący:

synchronized {
    while (!condition) { mon.wait(); }
}
oxbow_lakes
źródło
131
Nie, nie może. Można to tylko przerwać.
Peter Štibraný
9
Kiedy przeszkadzasz, musisz wiedzieć, który wątek chcesz przerwać. Gdy dzwonisz, zawiadamiasz, potrzebujesz tylko obiektu i nie obchodzi Cię, czy istnieje inny wątek, który „czeka” na ten obiekt. czekaj / powiadamiaj służy do komunikacji, podczas gdy sen służy, ehm, spanie.
Peter Štibraný
28
@Geek - dlaczego na świecie mówisz, że wait () marnuje cykle procesora?
Robert Munteanu
25
Przerwanie ma na celu delikatne zachęcanie wątku do całkowitego zatrzymania działania i anulowania pozostałych operacji. wait/ notifysą zazwyczaj używane do oczekiwania na wykonanie jakiegoś innego wątku lub do spełnienia określonego warunku.
Louis Wasserman
13
Przeczytałem wszystkie odpowiedzi, jednak wciąż brakuje mi informacji. Wiele osób zapisało definicje z Javadoc, a także znaczenie dwóch angielskich słów, ale nie rozumiem, dlaczego powinienem używać snu zamiast czekać? Jaka jest różnica między testami porównawczymi i prędkościami? Jeśli mogę zrobić wszystko, co mogę zrobić ze snem, dlaczego miałbym kiedykolwiek wybierać sen?
Balazs Zsoldos
334

Jedną kluczową różnicą, o której jeszcze nie wspomniano, jest to, że podczas uśpienia Wątek nie zwalnia blokad, które trzyma, podczas oczekiwania zwalnia blokadę na wait()wywołanym obiekcie .

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


synchronized(LOCK) {
    LOCK.wait(); // LOCK is not held
}
Robert Munteanu
źródło
105
Oczekiwanie zwalnia tylko blokadę dla obiektu, na którym wywołujesz wait (). Nie zwalnia żadnych innych blokad.
Jon Skeet
16
W rzeczywistości nie musisz dzwonić w tryb uśpienia z poziomu zamka - zamki i czekanie / powiadomienie idą w parze, ale zamki i sen nie są ze sobą powiązane.
oxbow_lakes
7
@oxbow_lakes - Powiedziałbym, że nie powinieneś spać z zamkami, jest na to kilka przypadków użycia. Chciałem tylko wskazać różnice.
Robert Munteanu
5
@RobertMunteanu, Twoja odpowiedź wprowadza w błąd, że sleepzawiera blokady java , ale tak nie jest. Aby mieć porównanie uczciwą, chcielibyśmy porównać synchronized(OUTER_LOCK){ Thread.sleep(1000); }z synchronized(OUTER_LOCK){ synchronized(LOCK){LOCK.wait();} }i widzimy, że obie instrukcje nie zwolnić OUTER_LOCK. Jeśli jest jakaś różnica, możemy powiedzieć, że sleepnie używa jawnie blokad java , ale pytanie dotyczy cytatu „jak ich implementacja różni się na niższym poziomie?”. zamknąć cudzysłów.
Pacerier,
2
@Pacerier wait()jest powiązany z warunkiem najbardziej wewnętrznej blokady, z której jest wywoływany, w twoim przykładzie kodu wait()można go zwolnić, LOCKa nie tylko OUTER_LOCK. Tak właśnie jest zaprojektowany monitor Java. Uczciwe porównanie byłoby synchronized(OUTER_LOCK){ synchronized(LOCK) { Thread.sleep(1000); } }i synchronized(OUTER_LOCK){ synchronized(LOCK) { LOCK.wait(); } }. W tym przypadku sleep()będą trzymać oba zamki, podczas gdy wait()zostaną zwolnione, LOCKale nadal będą trzymaneOUTER_LOCK
Danze
243

Uznałem ten post za pomocny. Stawia różnicę pomiędzy Thread.sleep(), Thread.yield()oraz Object.wait()w kategoriach ludzkich. Cytować:

Wszystko to ostatecznie dociera do harmonogramu systemu operacyjnego, który rozdaje przedziały czasu dla procesów i wątków.

sleep(n)mówi: „Skończyłem ze szczelinami czasowymi i proszę, nie dawaj mi kolejnego przez co najmniej n milisekund”.System operacyjny nie próbuje nawet zaplanować uśpionego wątku, dopóki nie upłynie żądany czas.

yield()mówi: „Skończyłem z czasem, ale wciąż mam do zrobienia”.System operacyjny może od razu podać wątkowi inny przedział czasu lub podać inny wątek lub przetworzyć procesor, który zrezygnował z wątku.

wait()mówi „Skończyłem z czasem. Nie dawaj mi kolejnego przedziału czasu, dopóki ktoś nie zadzwoni powiadomić (). ” Podobnie jak w przypadku sleep(), system operacyjny nie będzie nawet próbował zaplanować twojego zadania, chyba że ktoś zadzwoninotify() (lub wystąpi jeden z kilku innych scenariuszy budzenia).

Wątki tracą także pozostałą część czasu, gdy wykonują blokowanie IO i w kilku innych okolicznościach. Jeśli wątek działa przez cały przedział czasu, system operacyjny siłą przejmuje kontrolę z grubsza tak, jakbyyield() został wywołany, aby mogły działać inne procesy.

Rzadko potrzebujesz yield(), ale jeśli masz aplikację wymagającą dużej mocy obliczeniowej z logicznymi granicami zadań, wstawienie yield() może poprawić czas reakcji systemu (kosztem czasu - przełączanie kontekstu, nawet tylko na system operacyjny iz powrotem, nie jest bezpłatne). Jak zawsze mierz i testuj cele, na których Ci zależy.

E-bogaty
źródło
Wydajność jest w zasadzie zależna od platformy ... javamex.com/tutorials/threads/yield.shtml
Pacerier
wyjaśnienie sleep(n)to domyślnie mówi, że aktualnie uruchomiony wątek dobrowolnie zrzeka się monitora zamka, co nie jest prawdą . Cytat z javadoc Wątku : „Wątek nie traci własności żadnych monitorów”.
Clint Eastwood
2
@Jathanathan nie wspomniał o monitorach w odpowiedzi, a to dlatego, sleepże nie ma żadnych specjalnych zachowań dotyczących monitora niż jakiekolwiek inne wywołanie metody Java, to znaczy, że nie wchodzi w interakcje ani nie modyfikuje ich w żaden sposób. Jeśli powiesz coś na temat monitorów, powinieneś określić, że waitoprócz tego, co powiedziano powyżej, tymczasowo zniesie blokadę obiektu, do którego się wzywa.
pqnet
Jak działa powiadomienie na poziomie harmonogramu systemu operacyjnego? Czy powiadomienie wywołuje jakiś moduł obsługi zdarzeń o określonym identyfikatorze wątku, pozwalając programowi planującemu przywrócić odpowiedni wątek z powrotem do działającej kolejki? Mam też inne pytanie, gdzie mieści się koncepcja spinlocka? Czy miałoby to zastosowanie tylko do snu, czy też samo czeka na użycie blokady na bardzo niskim poziomie?
CMCDragonkai
@Erich, użyj wait(n)do porównania sleep(n). Nie ma sensu porównywanie za pomocą opcji no-arg.
Pacerier
68

Jest tu wiele odpowiedzi, ale nie mogłem znaleźć wyróżnienia semantycznego, o którym mowa.

Nie chodzi o sam wątek; obie metody są wymagane, ponieważ obsługują bardzo różne przypadki użycia.

sleep()wysyła Wątek w tryb uśpienia, tak jak wcześniej, po prostu pakuje kontekst i przestaje działać na określony czas. Aby obudzić go przed upływem czasu, musisz znać odniesienie do wątku. To nie jest typowa sytuacja w środowisku wielowątkowym. Jest to najczęściej używane do synchronizacji czasu (np. Obudzić się dokładnie w 3,5 sekundy) i / lub zakodowanej uczciwości (po prostu śpij przez chwilę i pozwól innym wątkom działać).

wait(), wręcz przeciwnie, jest mechanizmem synchronizacji wątku (lub wiadomości), który pozwala powiadomić Wątek, o którym nie masz zapisanego odniesienia (ani opieki). Możesz to traktować jako wzorzec publikowania-subskrybowania ( wait== subskrybuj inotify() == publikuj). Zasadniczo za pomocą powiadomienia () wysyłasz wiadomość (która może nawet nie zostać odebrana i zwykle nie obchodzi Cię to).

Podsumowując, zwykle używasz sleep()do synchronizacji czasu i synchronizacji wait()wielu wątków.

Mogą być zaimplementowane w ten sam sposób w podstawowym systemie operacyjnym lub wcale (ponieważ poprzednie wersje Java nie miały prawdziwej wielowątkowości; prawdopodobnie niektóre małe maszyny wirtualne też tego nie robią). Nie zapominaj, że Java działa na maszynie wirtualnej, więc Twój kod zostanie przekształcony w coś innego, zgodnie z VM / OS / HW, na którym działa.

estani
źródło
54

Tutaj mam wymienione kilka ważnych różnic wait()i sleep()metod.
PS: Kliknij również na linki, aby zobaczyć kod biblioteki (działa wewnętrznie, po prostu pobaw się trochę dla lepszego zrozumienia).

czekać()

  1. wait() Metoda zwalnia blokadę.
  2. wait()jest metodą Objectklasy.
  3. wait() jest metodą niestatyczną - public final void wait() throws InterruptedException { //...}
  4. wait()należy powiadomić za pomocą notify()lub notifyAll()metod.
  5. wait() Metoda musi zostać wywołana z pętli, aby poradzić sobie z fałszywym alarmem.

  6. wait() Metoda musi być wywołana z kontekstu synchronizowanego (tj. zsynchronizowana metoda lub blok), w przeciwnym razie wyrzuci IllegalMonitorStateException

sen()

  1. sleep() Metoda nie zwalnia blokady.
  2. sleep()jest metodą java.lang.Threadklasy.
  3. sleep() jest metodą statyczną - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
  4. po określonym czasie sleep() zostanie zakończone.
  5. sleep()lepiej nie dzwonić z pętli (tj. patrz kod poniżej ).
  6. sleep()może być wywoływany z dowolnego miejsca. nie ma szczególnych wymagań.

Ref: Różnica między oczekiwaniem a snem

Fragment kodu do wywołania metody oczekiwania i uśpienia

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

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

przejście wątku do różnych stanów wątku

roottraveller
źródło
Czy to prawda, że ​​uśpiony wątek może zostać obudzony przez wywołania powiadomienia ()? Niektóre inne posty tutaj sugerują, że śpiącego wątku nie można obudzić, ale przerwać.
berimbolo
Tak, Thread.sleep()służy do udostępniania czasu procesora innym wątkom. okres uśpienia może zostać zakończony przez przerwania (tj. przez JVM). Przeczytaj ten stackoverflow.com/questions/4264355/…
roottraveller
Ten post mówi również, że interrupt () jest tym, co budzi uśpiony wątek? Odniosłem się do opublikowanego przez ciebie diagramu stanu wątku, w którym jest napisane powiadomić lub powiadomić. Wszystkie przywracają uśpiony (nie czekający) wątek z powrotem do gotowości do uruchomienia. Chcę się tylko upewnić, że to rozumiem.
berimbolo
@berimbolo notify()lub notifyAll()Objectmetodami klasowymi. stąd są dostępne będą obj wszystkich klas (tj. tutaj również z Threadklasą). zobacz kod grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
roottraveller
2
OK Muszę przeczytać więcej o planowaniu wątków, ponieważ nie mogę znaleźć przykładów powiadomień () ani powiadomień All () wybudzających uśpione wątki tylko przerywają () robiąc to. Wszystkie przykłady dotyczą powiadomień () i powiadomieńAll () z wątkami oczekującymi na jakiś obiekt monitora.
berimbolo
29

Istnieją pewne kluczowe notatki różnicowe, które podsumowuję po pracy nad czekaniem i snem, najpierw spójrz na próbkę za pomocą wait () i sleep ():

Przykład 1 : użycie funkcji wait () i 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();
}

Niech klarowność zawiera kilka kluczowych uwag:

  1. Wezwać :
    • wait (): Wywołanie bieżącego wątku zawierającego obiekt HandObject
    • sleep (): Wywołanie zadania wykonywania wątku get beer (metoda klasy, więc wpływ na bieżący działający wątek)
  2. Zsynchronizowane :
    • wait (): po zsynchronizowanym dostępie do wielu wątków ten sam obiekt (HandObject) (gdy potrzebna jest komunikacja między więcej niż jednym wątkiem (kodowanie wątku, wykonanie wątku uzyskać piwo) dostęp do tego samego obiektu HandObject)
    • sleep (): gdy warunek oczekiwania jest kontynuowany (dostępne piwo oczekujące)
  3. Przytrzymaj blokadę :
    • wait (): zwolnij blokadę, aby inny obiekt miał szansę wykonać (HandObject jest darmowy, możesz wykonać inną pracę)
    • sleep (): trzymaj blokadę co najmniej t razy (lub aż do przerwania) (Moje zadanie wciąż się nie kończy, kontynuuję blokadę i czekam na pewien warunek, aby kontynuować)
  4. Stan budzenia :
    • wait (): aż do wywołania powiadomienia (), replaceAll () z obiektu
    • sleep (): do upłynięcia przynajmniej czasu lub przerwania połączenia
  5. Ostatnim punktem jest użycie, gdy jak estani wskazują:

zwykle używasz sleep () do synchronizacji czasu i wait () do synchronizacji wielu wątków.

Proszę popraw mnie jeżeli się mylę.

NguyenDat
źródło
25

Różnica między funkcją wait () a sleep ()

  • Podstawową różnicą jest to, że wait()pochodzi Objecti sleep()jest statyczna metoda Thread.

  • Główną różnicą jest to, że wait()zwalnia blokadę, podczas gdy sleep()nie zwalnia żadnej blokady podczas oczekiwania.

  • wait()jest używany do komunikacji między wątkami, podczas gdy sleep()ogólnie służy do wprowadzania pauzy przy wykonywaniu.

  • wait()należy wywołać od wewnątrz synchronizować, albo dostaniemy IllegalMonitorStateExceptionchwilęsleep() można wywołać w dowolnym miejscu.

  • Aby ponownie rozpocząć wątek wait(), musisz zadzwonić notify()lub notifyAll(). Co do sleep(),wątku zaczyna się po określonym przedziale czasu.

Podobieństwa

  • Oba sprawiają, że bieżący wątek przechodzi w Not Runnable .
  • Obie są metodami natywnymi .
Premraj
źródło
18

To bardzo proste pytanie, ponieważ obie te metody mają zupełnie inne zastosowanie.

Główną różnicą jest oczekiwanie na zwolnienie blokady lub monitora, podczas gdy sen nie zwalnia żadnej blokady ani monitora podczas oczekiwania. Czekanie służy do komunikacji między wątkami, podczas gdy sen służy do wprowadzenia pauzy przy wykonywaniu.

To było tylko jasne i podstawowe wyjaśnienie, jeśli chcesz czegoś więcej, czytaj dalej.

W przypadku wait()metody wątek przechodzi w stan oczekiwania i nie wróci automatycznie, dopóki nie wywołamy notify()metody (lub notifyAll()jeśli masz więcej niż jeden wątek w stanie oczekiwania i chcesz obudzić wszystkie te wątki). I trzeba zsynchronizować lub blokady obiektu lub blokada klasa Aby uzyskać dostęp do wait()albo notify()lub notifyAll()metod. I jeszcze jedno:wait() metoda jest używana do komunikacji między wątkami, ponieważ jeśli wątek przejdzie w stan oczekiwania, potrzebny będzie inny wątek, aby go obudzić.

Ale w takim przypadku sleep()jest to metoda używana do wstrzymania procesu przez kilka sekund lub żądany czas. Ponieważ nie musisz prowokować żadnej metody notify()ani notifyAll()metody odzyskania tego wątku. Lub nie potrzebujesz żadnego innego wątku, aby go oddzwonić. Na przykład, jeśli chcesz, aby coś się wydarzyło po kilku sekundach, np. W grze po kolejce użytkownika, chcesz, aby użytkownik czekał na uruchomienie komputera, możesz wspomniećsleep() metodzie.

I jeszcze jedna ważna różnica, o którą często pytamy w wywiadach: sleep()należy do Threadklasy i wait()należy doObject klasy.

To są wszystkie różnice między sleep()iwait() .

I istnieje podobieństwo między obiema metodami: obie są sprawdzane, więc musisz spróbować złapać lub rzucić, aby uzyskać dostęp do tych metod.

Mam nadzieję, że to Ci pomoże.

Vikas Gupta
źródło
16

źródło: http://www.jguru.com/faq/view.jsp?EID=47127

Thread.sleep()wysyła bieżący wątek do stanu „Nie można uruchomić przez pewien czas. Wątek zachowuje monitory, które uzyskał - tzn. Jeśli wątek jest obecnie w synchronizowanym bloku lub metodzie, żaden inny wątek nie może wejść do tego bloku lub metody. Jeśli zadzwoni inny wątekt.interrupt() , obudzi uśpiony wątek.

Pamiętaj, że uśpienie jest metodą statyczną, co oznacza, że ​​zawsze wpływa na bieżący wątek (ten, który wykonuje metodę uśpienia). Częstym błędem jest wywoływanie, t.sleep()gdzie t jest innym wątkiem; nawet wtedy uśpiony zostanie bieżący wątek, a nie wątek t.

t.suspend()jest przestarzałe. Za pomocą tego można zatrzymać wątek inny niż bieżący. Zawieszony wątek zachowuje wszystkie monitory, a ponieważ ten stan nie jest przerywany, jest podatny na zakleszczenie.

object.wait()wysyła bieżący wątek do stanu „Not Runnable” , jak sleep(), ale z niespodzianką. Czekanie jest wywoływane na obiekcie, a nie na wątku; nazywamy ten obiekt „obiektem blokady”. Przed lock.wait()wywołaniem bieżący wątek musi zsynchronizować się z obiektem blokady; wait() następnie zwalnia tę blokadę i dodaje wątek do „listy oczekujących” powiązanej z blokadą. Później inny wątek może zsynchronizować ten sam obiekt blokady i wywołanie lock.notify(). To budzi oryginalny, oczekujący wątek. Zasadniczo wait()/ notify()jest jak sleep()/ interrupt(), tylko aktywny wątek nie potrzebuje bezpośredniego wskaźnika do uśpionego wątku, a jedynie do wspólnego obiektu blokady.

om singh
źródło
14

Czekaj i śpij to dwie różne rzeczy:

  • W sleep() wątku przestaje działać na określony czas.
  • W wait()wątku przestaje działać aż istota Przedmiotem czekał na zostaje zgłoszone, zasadniczo innych nici.
Itay Maman
źródło
ale możesz przerwać uśpiony wątek. W takim przypadku wait () jest zbędny, marnuje również cykle procesora :-(
Geek
9
Czekanie nie marnuje cykli procesora.
Peter Štibraný
1
@Peter - Myślę, że tak. Oczekuje () na swoją część cykli procesora, a następnie system operacyjny przekazuje cykle procesora innym wątkom. Myślę, że to może być zależne od systemu operacyjnego, nie jestem pewien.
Geek
3
Byłoby to bardzo słabą implementacją funkcji wait (), gdyby zmarnowała cykle procesora. Funkcja „czekaj / powiadamiaj” jest często używana do komunikacji między wątkami.
Peter Štibraný
2
@Pacerier te dwie konstrukcje są przeznaczone do innego celu. Jeśli chcesz, aby wątek zatrzymał się na określony czas, którego używasz sleep, jeśli chcesz, aby zatrzymał się, dopóki niektóre dane wejściowe nie będą pochodzić od drugiego, którego używasz wait/ notify. interruptma na celu zasygnalizować wątkowi, że powinien przestać robić to, co robi i zakończyć. Jest obsługiwany przez sleep, waitale także blokuje funkcje We / Wy (i można zaimplementować funkcje o takim samym zachowaniu, wywołując metodę Thread.interrupted()). Jeśli chodzi o wydajność, funkcje są zwykle zoptymalizowane pod kątem celu, w którym zostały zaprojektowane.
pqnet
11

sleepjest metodą Thread, waitjest metodą Object, podobnie wait/notifyjak technika synchronizacji danych udostępnionych w Javie (przy użyciu monitora ), ale sleepjest prostą metodą wątku, aby się zatrzymać.

pvllnspk
źródło
8

sleep () jest metodą używaną do zatrzymania procesu przez kilka sekund lub żądany czas, ale w przypadku metody wait () wątek przechodzi w stan oczekiwania i nie wróci automatycznie, dopóki nie wywołamy powiadomienia () lub replaceAll ().

Główną różnicą jest to, że wait () zwalnia blokadę lub monitora podczas snu () nie zwalnia żadnej blokady lub monitora podczas oczekiwania. Czekanie służy do komunikacji między wątkami, podczas gdy sen jest używany do wprowadzenia pauzy w trakcie wykonywania.

Thread.sleep () wysyła bieżący wątek do stanu „Not Runnable” przez pewien czas. Wątek utrzymuje zgromadzone monitory - tzn. Jeśli wątek jest obecnie w zsynchronizowanym bloku lub metodzie, żaden inny wątek nie może wejść do tego bloku lub metody. Jeśli inny wątek wywoła t.interrupt (), obudzi uśpiony wątek. Pamiętaj, że uśpienie jest metodą statyczną, co oznacza, że ​​zawsze wpływa na bieżący wątek (ten, który wykonuje metodę uśpienia). Częstym błędem jest wywołanie t.sleep (), gdzie t jest innym wątkiem; nawet wtedy uśpiony zostanie bieżący wątek, a nie wątek t.

object.wait () wysyła bieżący wątek do stanu „Not Runnable”, jak sleep (), ale z niespodzianką. Czekanie jest wywoływane na obiekcie, a nie na wątku; nazywamy ten obiekt „obiektem blokady”. Przed wywołaniem funkcji lock.wait () bieżący wątek musi zsynchronizować się z obiektem blokady; wait () następnie zwalnia tę blokadę i dodaje wątek do „listy oczekujących” powiązanej z blokadą. Później inny wątek może zsynchronizować ten sam obiekt blokady i wywołać funkcję lock.notify (). To budzi oryginalny, oczekujący wątek. Zasadniczo czekanie () / powiadomienie () jest jak sleep () / interrupt (), tylko aktywny wątek nie potrzebuje bezpośredniego wskaźnika do uśpionego wątku, ale tylko do obiektu blokady współużytkowanej.

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

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

Pozwól kategoryzować wszystkie powyższe punkty:

Call on:

  • wait (): Wywołanie obiektu; bieżący wątek musi zostać zsynchronizowany na obiekcie blokady.
  • sleep (): Wywołanie wątku; zawsze aktualnie wykonuje wątek.

Synchronized:

  • wait (): po zsynchronizowaniu wielu wątków uzyskaj dostęp do tego samego obiektu jeden po drugim.
  • sleep (): po zsynchronizowaniu wielu wątków poczekaj na zakończenie uśpienia wątku.

Hold lock:

  • wait (): zwolnij blokadę, aby inne obiekty miały szansę wykonać.
  • sleep (): trzymaj blokadę co najmniej t razy, jeśli określono limit czasu lub ktoś przerwie.

Wake-up condition:

  • wait (): aż do wywołania powiadomienia (), replaceAll () z obiektu
  • sleep (): do upłynięcia przynajmniej czasu lub przerwania połączenia ().

Usage:

  • sleep (): do synchronizacji czasu i;
  • wait (): dla synchronizacji wielowątkowej.

Ref: diff sleepiwait

Reegan Miranda
źródło
6

Krótko mówiąc, czekaj to czekaj, dopóki inny wątek cię nie wywoła, podczas gdy sen to „nie wykonuj następnej instrukcji” przez określony czas.

Ponadto sleep jest metodą statyczną w klasie Thread i działa na wątku, podczas gdy wait () znajduje się w klasie Object i jest wywoływany na obiekcie.

Kolejny punkt, kiedy wywołujesz oczekiwanie na jakiś obiekt, zaangażowany wątek synchronizuje obiekt, a następnie czeka. :)

Ratnesh Maurya
źródło
1
Dlaczego potrzebujesz obu? Dlaczego sleep () nie jest wystarczający?
Geek
2
Powiadomienie służy do komunikacji między wątkami. Aby zadzwonić, poczekaj, potrzebujesz jakiegoś obiektu, zsynchronizuj go, a następnie zadzwoń do niego. Aby otrzymać powiadomienie, potrzebujesz innego wątku do synchronizacji tego samego obiektu i wywołania powiadomienia.
Peter Štibraný
6

waiti sleepmetody są bardzo różne:

  • sleep nie ma możliwości „przebudzenia”,
  • podczas gdy waitma sposób na „przebudzenie” podczas okresu oczekiwania przez inny wątek notifylub notifyAll.

Pomyśl o tym, nazwy są mylące pod tym względem; jednak sleepto standardowa nazwa i waitjest jak WaitForSingleObjectalbo WaitForMultipleObjectsw Win API.

Roee Adler
źródło
3
Ale możemy przerwać sen, prawda? więc jaka jest różnica między tym snem / przerwaniem a oczekiwaniem / powiadomieniem?
Pacerier
2
Możesz przerwać śpiącemu, ale możesz powiadomić tylko osobę oczekującą. Wątki są takie same.
Rishi
5

Z tego postu: http://javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/

Metoda wait ().

1) Wątek, który wywołuje metodę wait (), zwalnia blokadę.

2) Wątek odzyskuje blokadę po tym, jak inne wątki wywołują metody powiadomienia () lub notyfikuj wszystkie () na tej samej blokadzie.

3) W ramach synchronizowanego bloku należy wywołać metodę wait ().

4) Metoda wait () jest zawsze wywoływana na obiektach.

5) Oczekiwane wątki mogą zostać obudzone przez inne wątki, wywołując metody notice () lub replaceAll ().

6) Aby wywołać metodę wait (), wątek musi mieć blokadę obiektu.

Metoda sleep ()

1) Wątek, który wywołuje metodę sleep (), nie zwalnia blokady, którą trzyma.

2) metodę sleep () można wywołać w obrębie synchronizowanego bloku lub poza nim.

3) Metoda sleep () jest zawsze wywoływana dla wątków.

4) Śpiące wątki nie mogą zostać obudzone przez inne wątki. Jeśli to zrobisz, wątek zgłosi wyjątek InterruptedException.

5) Aby wywołać metodę sleep (), wątek nie musi mieć blokady obiektu.

użytkownik2485429
źródło
4
  1. wait()jest metodą Objectklasy.
    sleep()jest metodą Threadklasy.

  2. sleep()pozwala wątkowi przejść do sleepstanu przez x milisekund.
    Gdy wątek przechodzi w stan uśpienia it doesn’t release the lock.

  3. wait()pozwala nić zwolnić blokadę i goes to suspended state.
    Wątek będzie aktywny, gdy zostanie wywołana metoda notify()lub notifAll()dla tego samego obiektu.

VdeX
źródło
4

Jedną z potencjalnych dużych różnic między trybem uśpienia / przerwania a oczekiwaniem / powiadomieniem jest to

Generowanie wyjątku, gdy nie jest potrzebne, jest nieefektywne. Jeśli masz wątki komunikujące się ze sobą z dużą prędkością, generowanie wielu wyjątków powodowałoby ciągłe wywoływanie przerwania, co jest całkowitym marnotrawstwem procesora.

znak
źródło
+1, Właściwie ważny punkt, choć argumentowanie na temat wewnętrznych implementacji może być bardziej odpowiednie do analizy wydajności ...
Pacerier,
Innymi słowy, narzut związany z tworzeniem wyjątków może być znacznie mniejszy niż narzut związany z implementacją jednego lub drugiego systemu.
Pacerier
3

Masz rację - Sleep () powoduje, że wątek przechodzi w stan „uśpienia”, a procesor wyłącza się i przetwarza inne wątki (inaczej zwane przełączaniem kontekstu), jak sądzę, Wait utrzymuje procesor przetwarzający bieżący wątek.

Mamy oba, ponieważ chociaż może wydawać się rozsądne, aby pozwolić innym osobom korzystać z procesora, gdy go nie używasz, w rzeczywistości istnieje przełączanie kontekstu narzutu - w zależności od tego, jak długo trwa sen, może być droższy w cyklach procesora do przełączania wątków, niż po prostu, aby twój wątek nic nie robił przez kilka ms.

Zauważ też, że sen wymusza zmianę kontekstu.

Ponadto - generalnie nie jest możliwe sterowanie przełączaniem kontekstu - podczas oczekiwania system operacyjny może (i będzie dłużej oczekiwał) wybrać przetwarzanie innych wątków.

Justin
źródło
4
Funkcja wait () nie utrzymuje procesora przetwarzającego bieżący wątek. To jest jak sen, ponieważ powoduje także zmianę kontekstu: javamex.com/tutorials/threads/context_switch.shtml . Przez pół roku pytałem o przepełnienie stosu i wydaje się, że nikt nie wie, jaka jest różnica między oczekiwaniem / powiadomieniem a snem / przerwaniem.
Pacerier
chociaż uśpienie nie utrzymuje procesora w przetwarzaniu bieżącego wątku, myślę, że i tak jest to trochę obciążenie dla procesora, ponieważ procesor musi śledzić moment, w którym należy zakończyć uśpienie. Nie ma zewnętrznego wyzwalacza, takiego jak „powiadomienie” w oczekiwaniu. Nie?
Vladimir Nabokov,
@VladimirNabokov, wyzwalacz zewnętrzny to interrupt. Czas zakończenia jest nza wait(n). Minęło już 8 lat i wciąż nikt nie zna odpowiedzi!
Pacerier
3

Metody są używane do różnych rzeczy.

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

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

Thread.sleep (n) można przerwać, ale Object.wait () musi zostać powiadomiony. Możliwe jest określenie maksymalnego czasu oczekiwania: Object.wait(5000)więc można by użyć wait, er, sleepale wtedy trzeba zawracać sobie głowę blokadami.

Żadna z metod nie używa procesora podczas snu / oczekiwania.

Metody są implementowane przy użyciu kodu natywnego, przy użyciu podobnych konstrukcji, ale nie w ten sam sposób.

Szukaj sam: czy dostępny jest kod źródłowy metod natywnych? Plik /src/share/vm/prims/jvm.cppjest punktem początkowym ...

KarlP
źródło
Czas wątku uśpienia można również ustawić na czas nieokreślony. Czas Object.wait można również ustawić na określony. Ta odpowiedź nie wyjaśnia, dlaczego potrzebujemy 2 młotów, które robią to samo.
Pacerier,
Thread.sleep(big_num) musi zostać przerwane. Object.wait(small_num) może zostać powiadomiony.
Pacerier
3

Tutaj wait () będzie w stanie oczekiwania, dopóki nie powiadomi o tym inny wątek, ale gdzie jako sleep () będzie miał trochę czasu .. po tym, gdy automatycznie przejdzie w stan gotowości ...

Rakhi Jaligama
źródło
3

Różnice oczekiwania () i snu ()?

Thread.sleep () Po zakończeniu pracy tylko zwolnij zamek dla wszystkich. dopóki nie zwolni nikogo z blokady.

  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 () Gdy przejdzie do etapu oczekiwania, zwolni klucz i będzie czekał przez kilka sekund na podstawie parametru.

Na przykład:

bierzesz kawę w prawą rękę, możesz wziąć inną osobę z tej samej ręki, kiedy odłożysz, zabierz tylko inny przedmiot tego samego typu. również. to jest sen () śpisz czas nie pracowałeś, robisz tylko spanie ... to samo tutaj również.

czekać(). kiedy jesteś przygnębiony i bierzesz inny środek, gdy czekasz, to czekaj

grasz film lub cokolwiek w swoim systemie tak samo jak odtwarzacz, nie możesz odtwarzać więcej niż jednego naraz, to jest tutaj, kiedy zamykasz i wybierasz inny dowolny film lub utwór, podczas gdy nazywa się czekać

VISALIG
źródło
3

waitzwalnia blokadę i sleepnie. Wątek w stanie oczekiwania może się obudzić natychmiast po wywołaniu notifylub notifyAll. Ale w przypadku sleepnici utrzymuje blokadę i będzie kwalifikować się dopiero po upływie czasu snu.

shikjohari
źródło
Więc jeśli wątek śpi przez 10 sekund i zdarzy się przerwany wyjątek ????
Geek
@Geek An InterruptedExceptionzostaje wyrzucony, tak jak napisano w Javadoc.
user207421,
@EJP: Czy jesteś tym samym EJP, który był na forach sun.java.com? Przynajmniej twój wynik sugeruje to samo :-)
Geek
2

sleep()Metoda powoduje przejście bieżącego wątku ze stanu roboczego do stanu zablokowania na określony czas. Jeśli bieżący wątek ma blokadę dowolnego obiektu, wówczas go trzyma, co oznacza, że ​​inne wątki nie mogą wykonać żadnej zsynchronizowanej metody w tym obiekcie klasy.

wait() Metoda powoduje, że bieżący wątek przechodzi w stan bloku albo na określony czas, albo do powiadomienia, ale w tym przypadku wątek zwalnia blokadę obiektu (co oznacza, że ​​inne wątki mogą wykonywać dowolne zsynchronizowane metody obiektu wywołującego.

Użytkownik 1000
źródło
2

Moim zdaniem główna różnica między obydwoma mechanizmami polega na tym, że tryb uśpienia / przerwania jest najbardziej podstawowym sposobem obsługi wątków, podczas gdy oczekiwanie / powiadomienie to abstrakcja mająca na celu ułatwienie komunikacji między wątkami. Oznacza to, że sen / przerwanie może zrobić wszystko, ale trudniejsze jest wykonanie tego konkretnego zadania.

Dlaczego oczekiwanie / powiadomienie jest bardziej odpowiednie? Oto kilka osobistych uwag:

  1. Wymusza centralizację. Pozwala na koordynację komunikacji między grupą wątków za pomocą pojedynczego obiektu wspólnego. To bardzo upraszcza pracę.

  2. Wymusza synchronizację. Ponieważ zmusza programistę do zawinięcia połączenia w celu oczekiwania / powiadomienia w zsynchronizowanym bloku.

  3. Jest niezależny od pochodzenia i numeru wątku. Dzięki takiemu podejściu możesz dowolnie dodawać więcej wątków bez edytowania innych wątków lub śledzenia istniejących. Jeśli używałeś trybu uśpienia / przerwania, najpierw musisz zachować odniesienia do uśpionych wątków, a następnie przerwać je pojedynczo, ręcznie.

Przykładem z prawdziwego życia, który warto wyjaśnić, jest klasyczna restauracja i metoda, którą pracownicy używają do komunikowania się między nimi: kelnerzy pozostawiają życzenia klientów w centralnym miejscu (tablica korkowa, stół itp.), zadzwonić, a pracownicy z kuchni przychodzą, aby przyjąć takie prośby. Po przygotowaniu kursu personel kuchni ponownie dzwoni, aby kelnerzy byli świadomi i zabrali go do klientów.

negora
źródło
2

Przykład dotyczący snu nie zwalnia blokady, a czeka

Oto dwie klasy:

  1. Main : Zawiera główną metodę i dwa wątki.
  2. Singleton : Jest to klasa singleton z dwiema statycznymi metodami getInstance () i getInstance (boolean 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();
    
     }
    }

i

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;

 }
}

Teraz uruchom ten przykład, uzyskasz wynik poniżej:

_instance :null
Both singleton are same

W tym przypadku wystąpienia Singleton utworzone przez wątek A i wątek B są takie same. Oznacza to, że wątek B czeka na zewnątrz, aż wątek A zwolni blokadę.

Teraz zmień Singleton.java, komentując Thread.sleep (500); metoda i odkomentowanie Singleton.class.wait (500); . Tutaj z powodu Singleton.class.wait (500); metoda threadA zwolni wszystkie blokady i przejdzie w stan „Non Runnable”, wątek B dostanie zmianę do wprowadzenia w bloku synchronicznym.

Teraz uruchom ponownie:

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

W tym przypadku instancje Singleton utworzone przez wątek A i wątek NIE są takie same, ponieważ wątek B otrzymał zmianę, aby wejść do bloku synchronicznego i po 500 milisekundach wątek A zaczął od swojej ostatniej pozycji i utworzył jeszcze jeden obiekt Singleton.

Dhiral Pandya
źródło
2

Powinny być wywoływane z bloku zsynchronizowanego: wait() metoda jest zawsze wywoływana z bloku zsynchronizowanego, tzn. wait()Metoda musi zablokować monitor obiektu przed obiektem, na którym jest wywoływana. Ale sleep()metodę można wywołać z zewnętrznego synchronizowanego bloku, tzn. sleep()Metoda nie wymaga monitorowania obiektu.

IllegalMonitorStateException: jeśli wait()metoda jest wywoływana bez uzyskiwania blokady obiektu, niż IllegalMonitorStateExceptionjest generowana w czasie wykonywania, ale sleep()metoda nigdy nie zgłasza takiego wyjątku.

Należy do której klasy: wait() metoda należy do java.lang.Objectklasy, ale sleep()metoda należy do java.lang.Threadklasy.

Wywoływany na obiekcie lub wątku: wait() metoda jest wywoływana na obiektach, ale sleep()metoda jest wywoływana na wątkach, a nie obiektach.

Stan wątku: gdy wait()metoda jest wywoływana na obiekcie, wątek, który trzymał monitor obiektu przechodzi od stanu uruchomionego do stanu oczekiwania i może powrócić do stanu wykonalnego tylko wtedy, gdy notify()lub obiekt notifyAll()zostanie wywołany na tym obiekcie. Później harmonogram wątków planuje przejście tego wątku ze stanu uruchomionego do uruchomionego. kiedy sleep()nazywa się na wątku przechodzi od stanu wykonywania do czekania i może powrócić do stanu runnable gdy czas snu jest gotowy.

W przypadku wywołania z bloku synchronicznego: w przypadku wait()wywołania metody wątek opuszcza blokadę obiektu. Ale sleep()metoda wywołana z synchronizowanego bloku lub wątku metody nie pozostawia blokady obiektu.

Aby uzyskać więcej Referencje

AVI
źródło
prawdopodobnie lepszy referencyjny adres URL niż ten.
Drew
2

Ze strony dokumentacji Oracle w metodzie wait ()Object :

public final void wait()
  1. Powoduje, że bieżący wątek czeka, aż inny wątek wywoła notify()metodę lub notifyAll()metodę dla tego obiektu. Innymi słowy, ta metoda zachowuje się dokładnie tak, jakby po prostu wykonała wywołanie wait(0).
  2. Bieżący wątek musi być właścicielem monitora tego obiektu. Wątek zwalnia własność tego monitora i czeka, aż inny wątek powiadomi wątki oczekujące na monitorze tego obiektu, aby się obudził
  3. możliwe są przerwania i fałszywe budzenie
  4. Ta metoda powinna być wywoływana tylko przez wątek, który jest właścicielem monitora tego obiektu

Ta metoda rzuca

  1. IllegalMonitorStateException - jeśli bieżący wątek nie jest właścicielem monitora obiektu.

  2. InterruptedException- jeśli jakikolwiek wątek przerwał bieżący wątek przed lub w trakcie, gdy bieżący wątek czekał na powiadomienie. Status przerwania bieżącego wątku jest usuwany po zgłoszeniu tego wyjątku.

Ze strony dokumentacji Oracle w metodzie sleep ()Thread klasy:

public static void sleep(long millis)
  1. Powoduje uśpienie aktualnie wykonującego się wątku (tymczasowe wstrzymanie wykonywania) na określoną liczbę milisekund, z zastrzeżeniem precyzji i dokładności systemowych zegarów i harmonogramów.
  2. Wątek nie traci własności żadnych monitorów.

Ta metoda rzuca:

  1. IllegalArgumentException - jeżeli wartość millis jest ujemna

  2. InterruptedException- jeśli jakikolwiek wątek przerwał bieżący wątek. Status przerwania bieżącego wątku jest usuwany po zgłoszeniu tego wyjątku.

Inna kluczowa różnica:

wait()jest metodą niestatyczną (metoda instancji) w przeciwieństwie do metody statycznej sleep()(metoda klasy).

Ravindra babu
źródło
1

wait()jest umieszczona pomiędzy zsynchronizowany sposób, podczas gdy sleep()podaje się wewnątrz nie zsynchronizowany sposób, ponieważ wait()sposób zwolnić blokadę obiektu, ale sleep()i yield()zwalnia lock().

Aravind Mano
źródło
sleep()może znajdować się w synchronizedbloku lub metodzie. Odpowiedź nic nie wyjaśnia.
user207421,
1
  • Metoda wait(1000)powoduje uśpienie bieżącego wątku do jednej sekundy .
    • Wątek może spać krócej niż 1 sekundę, jeśli odbierze wywołanie metody notify()lubnotifyAll() metody.
  • Wywołanie opcji sleep(1000)powoduje uśpienie bieżącego wątku na dokładnie 1 sekundę .
    • Również uśpiony wątek nie blokuje żadnego zasobu . Ale oczekujący wątek tak.
Rupesz
źródło
1
sleep(1000)nie gwarantuje snu przez dokładnie 1 sekundę. Może to być wcześniej przerwane.
Lucio
1
Te posty są bardzo mylące. Wszystkie pozostałe posty w tym wątku informują, że śpiący wątek NIE blokuje zamka, a oczekujący wątek NIE blokuje zamka. Podobnie post z diagramem sugeruje, że wywołania powiadomień () wybudzają uśpione wątki, ale inne posty (i diagramy stanów wątków) sugerują, że robią to tylko przerwanie () lub przekroczenie limitu czasu. Właśnie zamówiłem sobie kopię współbieżności Java w praktyce, coś, co powinienem był przeczytać dawno temu!
berimbolo,
1

W rzeczywistości wszystko to jest jasno opisane w dokumentach Java (ale zrozumiałem to dopiero po przeczytaniu odpowiedzi).

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

wait () - bieżący wątek musi posiadać monitor tego obiektu. Wątek zwalnia prawo własności do tego monitora i czeka, aż inny wątek powiadomi wątki oczekujące na monitorze tego obiektu, aby się obudził albo przez wywołanie metody notyfikacji, albo metody notyfikowania wszystkich. Wątek czeka następnie, aż będzie mógł odzyskać własność monitora i wznowi wykonywanie.

sleep () - Powoduje uśpienie aktualnie wykonywanego wątku (czasowo wstrzymaj wykonywanie) na określoną liczbę milisekund, z zastrzeżeniem precyzji i dokładności systemowych liczników czasu i harmonogramów. Wątek nie traci własności żadnych monitorów.

TT_
źródło