Jestem trochę zdezorientowany, jeśli chodzi o użycie yield()
metody w Javie, szczególnie w przykładowym kodzie poniżej. Czytałem również, że yield () jest „używany do zapobiegania wykonaniu wątku”.
Moje pytania to:
Uważam, że poniższy kod
yield()
daje takie same wyniki zarówno podczas używania, jak i gdy go nie używasz. Czy to jest poprawne?Jakie są właściwie główne zastosowania
yield()
?Czym
yield()
różni się od metodjoin()
iinterrupt()
?
Przykładowy kod:
public class MyRunnable implements Runnable {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
for(int i=0; i<5; i++) {
System.out.println("Inside main");
}
}
public void run() {
for(int i=0; i<5; i++) {
System.out.println("Inside run");
Thread.yield();
}
}
}
Otrzymuję ten sam wynik, używając powyższego kodu zarówno z użyciem, jak i bez użycia yield()
:
Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run
yield()
i nie. kiedy masz duże i zamiast 5, możesz zobaczyć efektyield()
metody.Odpowiedzi:
Źródło: http://www.javamex.com/tutorials/threads/yield.shtml
źródło
Widzę, że pytanie zostało reaktywowane z nagrodą, teraz pytam, jakie są praktyczne zastosowania
yield
. Podam przykład z mojego doświadczenia.Jak wiemy,
yield
wymusza na wątku wywołującym rezygnację z procesora, na którym działa, aby można było zaplanować uruchomienie innego wątku. Jest to przydatne, gdy bieżący wątek zakończył na razie swoją pracę, ale chce szybko wrócić na początek kolejki i sprawdzić, czy jakiś warunek się zmienił. Czym to się różni od zmiennej warunkowej?yield
umożliwia wątkowi powrót do stanu działania o wiele szybciej. Podczas oczekiwania na zmienną warunku wątek jest zawieszany i musi czekać, aż inny wątek zasygnalizuje, że powinien kontynuować.yield
po prostu mówi: „pozwól działać innemu wątkowi, ale pozwól mi wrócić do pracy bardzo szybko, gdy spodziewam się, że coś bardzo szybko się zmieni w moim stanie”. Wskazuje to na zajęty wirowanie, w którym stan może się szybko zmienić, ale zawieszenie wątku spowodowałoby duży spadek wydajności.Ale dość bełkotania, oto konkretny przykład: równoległy wzór czoła fali. Podstawowym przykładem tego problemu jest obliczanie poszczególnych „wysp” jedynek w dwuwymiarowej tablicy wypełnionej zerami i jedynkami. „Wyspa” to grupa komórek sąsiadujących ze sobą w pionie lub w poziomie:
Tutaj mamy dwie wyspy 1: lewy górny i prawy dolny.
Prostym rozwiązaniem jest wykonanie pierwszego przejścia przez całą tablicę i zastąpienie 1 wartości licznikiem zwiększającym się tak, że na końcu każda 1 została zastąpiona numerem kolejnym w wierszu głównym:
W następnym kroku każda wartość jest zastępowana przez minimum między sobą a wartościami sąsiadów:
Możemy teraz łatwo określić, że mamy dwie wyspy.
Część, którą chcemy uruchomić równolegle, to krok, w którym obliczamy minimum. Bez wchodzenia w zbyt wiele szczegółów każdy wątek otrzymuje wiersze w sposób przeplatany i opiera się na wartościach obliczonych przez wątek przetwarzający powyższy wiersz. W związku z tym każdy wątek musi być nieco opóźniony w stosunku do wątku przetwarzającego poprzednią linię, ale musi również nadążyć w rozsądnym czasie. Więcej szczegółów i implementację przedstawiam w tym dokumencie . Należy zauważyć, wykorzystanie
sleep(0)
co jest mniej więcej równoważne Cyield
.W tym przypadku
yield
została użyta w celu wymuszenia na każdym wątku z kolei wstrzymania, ale ponieważ w międzyczasie wątek przetwarzający sąsiedni rząd przesuwałby się bardzo szybko, zmienna warunkowa okazałaby się katastrofalnym wyborem.Jak widać,
yield
jest to dość drobnoziarnista optymalizacja. Używanie go w niewłaściwym miejscu, np. Oczekiwanie na rzadko zmieniający się warunek, spowoduje nadmierne wykorzystanie procesora.Przepraszam za długą paplaninę, mam nadzieję, że wyraziłem się jasno.
źródło
yield
gdy warunek nie jest spełniony, aby dać innym wątkom szansę na kontynuowanie obliczeń, zamiast używania większej prymitywy synchronizacji poziomu, prawda?yield
.O różnicach między
yield()
,interrupt()
ijoin()
- w ogóle, nie tylko w Javie:W przypadku języka Java zobacz
Łączący:
Jak korzystać z Thread.join? (tutaj w StackOverflow)
Kiedy dołączyć do wątków?
Wydajność:
Przerywanie:
Czy Thread.interrupt () jest zły? (tutaj w StackOverflow)
źródło
wait()
nie jest złączeniem, chodzi o blokadę obiektu, który próbuje uzyskać wywołujący wątek - czeka, aż blokada zostanie zwolniona przez innych i zostanie przejęta przez wątek. Odpowiednio poprawiłem moją odpowiedź.Po pierwsze, rzeczywisty opis to
Teraz jest bardzo prawdopodobne, że twój główny wątek wykona pętlę pięć razy, zanim
run
metoda nowego wątku zostanie wykonana, więc wszystkie wywołaniayield
będą miały miejsce dopiero po wykonaniu pętli w głównym wątku.join
zatrzyma bieżący wątek do momentu zakończeniajoin()
wykonywania wywoływanego wątku .interrupt
przerwie wątek, w którym jest wywoływany, powodując InterruptedException .yield
umożliwia przełączanie kontekstu na inne wątki, więc ten wątek nie będzie zużywał całego wykorzystania procesora przez proces.źródło
SwitchToThread()
połączenie jest lepsze niż uśpienie (0) i powinno to być błąd w Javie :)Nie ma praktycznej różnicy
Thread.yield()
między wersjami Java od 6 do 9.TL; DR;
Wnioski oparte na kodzie źródłowym OpenJDK ( http://hg.openjdk.java.net/ ).
Jeśli nie wziąć pod uwagę obsługi HotSpot sond USDT (informacje o śledzeniu systemu są opisane w przewodniku dtrace ) i właściwości JVM,
ConvertYieldToSleep
to kod źródłowyyield()
jest prawie taki sam. Zobacz wyjaśnienie poniżej.Java 9 :
Thread.yield()
wywołuje metodę specyficzną dla systemu operacyjnegoos::naked_yield()
:W systemie Linux:
W systemie Windows:
Java 8 i starsze:
Thread.yield()
wywołuje metodę specyficzną dla systemu operacyjnegoos::yield()
:W systemie Linux:
W systemie Windows:
Jak widać,
Thread.yeald()
w systemie Linux jest identyczny dla wszystkich wersji Java.Zobaczmy Windows
os::NakedYield()
z JDK 8:Różnica między Java 9 i Java 8
SwitchToThread()
polega na dodatkowym sprawdzeniu istnienia metody Win32 API . Ten sam kod jest obecny w Javie 6.Kod źródłowy
os::NakedYield()
w JDK 7 jest nieco inny, ale zachowuje się tak samo:Dodatkowa kontrola została pominięta ze względu na
SwitchToThread()
metodę, która jest dostępna od wersji Windows XP i Windows Server 2003 (patrz uwagi msdn ).źródło
Wydajność sugeruje procesorowi, że możesz zatrzymać bieżący wątek i rozpocząć wykonywanie wątków z wyższym priorytetem. Innymi słowy, przypisanie wartości o niskim priorytecie do bieżącego wątku, aby zostawić miejsce na bardziej krytyczne wątki.
NIE, oba przyniosą różne rezultaty. Bez yield (), gdy wątek uzyska kontrolę, wykona pętlę „Inside run” za jednym razem. Jednak w przypadku yield (), gdy wątek uzyska kontrolę, raz wydrukuje 'bieg wewnętrzny', a następnie przekaże kontrolę innemu wątkowi, jeśli taki istnieje. Jeśli nie ma wątku oczekującego, zostanie wznowiony ponownie. Tak więc za każdym razem, gdy wykonywane jest "Uruchomienie wewnętrzne", będzie szukał innych wątków do wykonania, a jeśli żaden wątek nie jest dostępny, bieżący wątek będzie wykonywany dalej.
yield () służy do zapewniania miejsca innym ważnym wątkom, join () służy do czekania na zakończenie wykonywania przez inny wątek, a przerywanie () służy do przerywania aktualnie wykonywanego wątku w celu zrobienia czegoś innego.
źródło
Without a yield(), once the thread gets control it will execute the 'Inside run' loop in one go
? Proszę o wyjaśnienie.Thread.yield()
powoduje przejście wątku ze stanu „Running” do stanu „Runnable”. Uwaga: nie powoduje przejścia wątku do stanu „Oczekiwanie”.źródło
RUNNING
stanu dlajava.lang.Thread
instancji. Nie wyklucza to jednak natywnego stanu „uruchomionego” wątku natywnego, dla któregoThread
instancja jest proxy.Thread.yield ()
Przystąp()
źródło
Głównym zastosowaniem yield () jest zawieszanie aplikacji obsługującej wiele wątków.
wszystkie te różnice w metodach to yield () wstrzymuje wątek podczas wykonywania innego wątku i powraca po zakończeniu tego wątku, join () połączy razem początek wątków, wykonując aż do końca i kolejnego wątku do uruchomienia po tym wątku zakończone, przerwanie () zatrzyma na chwilę wykonywanie wątku.
źródło
yield
należy je wykorzystać.