Mechanizm przerwania wątku jest preferowanym sposobem uzyskania (współpracującego) wątku, aby odpowiedział na żądanie zatrzymania tego, co robi. Każdy wątek (w tym myślę, że sam wątek) mógłby wywołać interrupt()
wątek.
W praktyce normalne przypadki użycia interrupt()
obejmują pewien rodzaj frameworka lub menedżera, który nakazuje wątkowi robocemu przerwanie tego, co robią. Jeśli wątek roboczy jest „świadomy przerwania”, zauważy, że został przerwany przez wyjątek lub przez okresowe sprawdzanie flagi przerwania. Zauważając, że został przerwany, grzeczny wątek porzuciłby to, co robi i zakończył się sam.
Zakładając powyższy przypadek użycia, twój kod prawdopodobnie zostanie przerwany, jeśli zostanie uruchomiony w środowisku Java lub z jakiegoś wątku roboczego. A kiedy zostanie przerwany, twój kod powinien porzucić to, co robi i doprowadzić do końca w najbardziej odpowiedni sposób. W zależności od tego, jak został wywołany Twój kod, można to zrobić, zwracając lub zgłaszając odpowiedni wyjątek. Ale chyba nie powinien dzwonić System.exit()
. (Twoja aplikacja niekoniecznie wie, dlaczego została przerwana, a na pewno nie wie, czy istnieją inne wątki, które muszą zostać przerwane przez framework).
Z drugiej strony, jeśli twój kod nie jest przeznaczony do uruchamiania pod kontrolą jakiegoś frameworka, możesz argumentować, że InterruptedException
jest to nieoczekiwany wyjątek; tj. błąd. W takim przypadku wyjątek należy traktować tak, jak inne błędy; np. zawiń go w niesprawdzony wyjątek i złap go i zarejestruj w tym samym miejscu, w którym masz do czynienia z innymi nieoczekiwanymi, niezaznaczonymi wyjątkami. (Alternatywnie, Twoja aplikacja może po prostu zignorować przerwanie i kontynuować to, co robiła).
1) Jeśli sam nigdy nie przerywam innych wątków, co może wywołać wyjątek InterruptedException?
Jednym z przykładów jest sytuacja, w której Runnable
obiekty są wykonywane przy użyciu ExecutorService
i shutdownNow()
jest wywoływana w usłudze. Teoretycznie każda pula wątków lub platforma zarządzania wątkami innej firmy może legalnie zrobić coś takiego.
2) Jeśli sam nigdy nie przerywam innych wątków, używając przerwania () ... co oznacza InterruptedException
then? Co mam zrobić po złapaniu jednego? Czy zamknąć moją aplikację?
Musisz przeanalizować kod źródłowy, aby dowiedzieć się, co interrupt()
wywołuje połączenia i dlaczego. Gdy już to ustalisz, możesz dowiedzieć się, co musi zrobić >> Twoja << część aplikacji.
Dopóki nie wiesz, dlaczego InterruptedException
jest rzucany, radziłbym potraktować to jako poważny błąd; np. wydrukuj stos do pliku dziennika i zamknij aplikację. (Oczywiście nie zawsze jest to właściwa odpowiedź ... ale chodzi o to, że jest to „błąd”, na który należy zwrócić uwagę programisty / opiekuna).
3) Jak mogę się dowiedzieć, kto / co dzwoni interrupt()
?
Nie ma na to dobrej odpowiedzi. Najlepsze, co mogę zasugerować, to ustawić punkt przerwania Thread.interrupt()
i spojrzeć na stos wywołań.
Jak zauważyli inni, przerwanie wątku (a właściwie przerwanie połączenia blokującego) jest zwykle używane do celów czystego wyjścia lub anulowania trwającej czynności.
Nie powinieneś jednak traktować
InterruptedException
samego siebie jako „polecenia wyjścia”. Zamiast tego powinieneś myśleć o przerwaniach jako o sposobie kontrolowania stanu działania wątków, w podobny sposób jak toObject.notify()
robi. W ten sam sposób, w jaki sprawdzałbyś aktualny stan po obudzeniu się z połączenia doObject.wait()
(nie zakładasz, że przebudzenie oznacza spełnienie warunku oczekiwania), po szturchnięciu Cię przerwaniem powinieneś sprawdzić, dlaczego zostałeś przerwany . Zwykle jest na to sposób. Na przykładjava.util.concurrent.FutureTask
maisCancelled()
metodę.Przykład kodu:
public void run() { .... try { .... // Calls that may block. } catch (InterruptedException e) { if (!running) { // Add preferred synchronization here. return; // Explicit flag says we should stop running. } // We were interrupted, but the flag says we're still running. // It would be wrong to always exit here. The interrupt 'nudge' // could mean something completely different. For example, it // could be that the thread was blocking on a read from a particular // file, and now we should read from a different file. // Interrupt != quit (not necessarily). } .... } public void stop() { running = false; // Add preferred synchronization here. myThread.interrupt(); }
źródło
Problem z pytaniem to „ja”. „I” zwykle odnosi się do pojedynczego wystąpienia klasy. Rozumiem przez to, że żaden konkretny fragment kodu (klasy) niskiego poziomu nie powinien polegać na implementacji całego systemu. Powiedziawszy, że musisz podjąć pewne decyzje „architektoniczne” (np. Na jakiej platformie uruchomić).
Możliwe nieoczekiwane przerwania pochodzące ze środowiska JRE to anulowane zadania w
java.util.concurrent
apletach i zamykanie ich.Obsługa przerwań wątków jest zwykle napisana niepoprawnie. Dlatego proponuję decyzję architektoniczną, aby w miarę możliwości unikać powodowania przerw. Jednak przerwania obsługi kodu powinny być zawsze napisane poprawnie. Nie można teraz usuwać przerw z platformy.
źródło
Możesz się tego nauczyć, tworząc własną klasę wątku (rozszerzającą
java.lang.Thread
) iinterrupt()
metodę nadpisywania , w której zapisujesz ślad stosu, powiedzmy, w polu String, a następnie przenosisz do super.interrupt ().public class MyThread extends Thread { public volatile String interruptStacktrace; // Temporary field for debugging purpose. @Override public void interrupt() { interruptStacktrace = dumpStack(); // You implement it somehow... super.interrupt(); } }
źródło
Jak już wspomniano, inna biblioteka może przerwać twoje wątki. Nawet jeśli biblioteka nie ma jawnego dostępu do wątków z twojego kodu, nadal mogą uzyskać listę uruchomionych wątków i przerwać je w ten sposób za pomocą następującej metody .
źródło
Myślę, że rozumiem, dlaczego jesteś trochę zdezorientowany, jeśli chodzi o przerwanie. Proszę rozważyć moje odpowiedzi w kolejce:
Po pierwsze możesz przerwać inne wątki; Wiem, że w JCiP jest napisane, że nigdy nie należy przerywać wątków, których nie jesteś właścicielem; jednak to stwierdzenie musi być właściwie zrozumiane. Oznacza to, że Twój kod, który może być uruchomiony w dowolnym wątku, nie powinien obsługiwać przerwania, ponieważ ponieważ nie jest właścicielem wątku, nie ma pojęcia o jego polityce przerywania. Możesz więc poprosić o przerwanie w innych wątkach, ale pozwól jego właścicielowi podjąć działanie przerywające; zawiera w sobie politykę przerwania, a nie kod zadania; przynajmniej bądź uprzejmy i ustaw flagę przerwania!
Istnieje wiele powodów, dla których mogą nadal występować przerwy, mogą to być przekroczenia limitu czasu, przerwania JVM itp.
Musisz tutaj bardzo uważać; Jeśli jesteś właścicielem wątku, który wywołał InterruptedException (IE), to wiesz, co zrobić po jego przechwyceniu, powiedz, że możesz zamknąć aplikację / usługę lub zastąpić ten zabity wątek nowym! Jeśli jednak nie jesteś właścicielem wątku, po złapaniu IE albo wyrzuć go ponownie wyżej na stos wywołań, albo po zrobieniu czegoś (może być rejestrowanie), zresetuj stan przerwania, aby kod, który jest właścicielem tego wątku, gdy kontrola do niego dotrze, może dowiaduje się, że wątek został przerwany, a zatem podejmuje działania tak, jak chce, ponieważ tylko on zna zasady przerywania.
Mam nadzieję, że to pomogło.
źródło
InterruptedException
Mówi, że procedura może zostać przerwany, ale nie koniecznie, że to będzie.Jeśli nie spodziewasz się przerwania, powinieneś traktować je tak, jak każdy inny nieoczekiwany wyjątek. Jeśli znajduje się w krytycznej sekcji, w której nieoczekiwany wyjątek może mieć haniebne konsekwencje, najlepiej będzie spróbować wyczyścić zasoby i bezpiecznie zamknąć (ponieważ otrzymanie przerwania sygnalizuje, że używana jest dobrze zaprojektowana aplikacja, która nie polega na przerwaniach w pewnym sensie nie zostało zaprojektowane, więc coś musi być nie tak). Alternatywnie, jeśli dany kod jest czymś niekrytycznym lub trywialnym, możesz zignorować (lub zarejestrować) przerwanie i kontynuować.
źródło