Czy możesz wyjaśnić, co java.lang.Thread.interrupt()
robi po wywołaniu?
Czy możesz wyjaśnić, co java.lang.Thread.interrupt()
robi po wywołaniu?
Odpowiedzi:
Thread.interrupt()
ustawia status / flag przerwanego wątku. Następnie kod działający w tym wątku docelowym MOŻE sondować status przerwania i odpowiednio go obsługiwać. Niektóre metody, takie jak blokujące, Object.wait()
mogą natychmiast zużyć przerwany status i wygenerować odpowiedni wyjątek (zwykle InterruptedException
)
Przerwanie w Javie nie ma charakteru wyprzedzającego. Innymi słowy, oba wątki muszą ze sobą współpracować, aby poprawnie przetworzyć przerwanie. Jeśli wątek docelowy nie odpytuje statusu przerwania, przerwanie jest skutecznie ignorowane.
Odpytywanie odbywa się za pomocą Thread.interrupted()
metody, która zwraca status przerwania bieżącego wątku ORAZ usuwa flagę przerwania. Zwykle wątek może wtedy zrobić coś takiego, jak wyrzucenie InterruptedException.
EDYCJA (na podstawie komentarzy Thilo): Niektóre metody API mają wbudowaną obsługę przerwań. Obejmuje to czubek mojej głowy.
Object.wait()
, Thread.sleep()
iThread.join()
java.util.concurrent
strukturInterruptedException
zamiast tego ClosedByInterruptException
.EDYCJA (od odpowiedzi @ thomas-pornin na dokładnie to samo pytanie dla kompletności)
Przerwanie wątku to delikatny sposób na podważenie wątku. Służy do dawania nitkom szansy na czyste wyjście , w przeciwieństwie do Thread.stop()
strzelania do nich za pomocą karabinu szturmowego.
Co to jest przerwanie?
Przerwanie jest wskazówką dla wątku, że powinien przerwać to, co robi i zrobić coś innego. Programiści decydują dokładnie, jak wątek zareaguje na przerwanie, ale jego zakończenie jest bardzo częste.
Jak to jest realizowane?
Mechanizm przerwania jest implementowany przy użyciu wewnętrznej flagi znanej jako status przerwania. Wywołanie Thread.interrupt ustawia tę flagę. Gdy wątek sprawdza przerwanie przez wywołanie metody statycznej Thread.interrupt, status przerwania jest usuwany. Niestatyczny Thread.isInterrupted, który jest używany przez jeden wątek do sprawdzania statusu przerwania innego, nie zmienia flagi statusu przerwania.
Cytat z Thread.interrupt()
API :
Przerywa ten wątek. Najpierw wywoływana jest metoda checkAccess tego wątku, co może spowodować zgłoszenie wyjątku SecurityException.
Jeśli ten wątek jest zablokowany w wywołaniu metod wait (), wait (long) lub wait (long, int) klasy Object, lub join (), join (long), join (long, int) , sleep (long) lub sleep (long, int), metody tej klasy, wówczas status przerwania zostanie skasowany i otrzyma wyjątek InterruptedException.
Jeśli ten wątek zostanie zablokowany podczas operacji we / wy na kanale przerywalnym, kanał zostanie zamknięty, status przerwania wątku zostanie ustawiony, a wątek otrzyma wyjątek ClosedByInterruptException.
Jeśli ten wątek zostanie zablokowany w Selektorze, zostanie ustawiony status przerwania wątku i natychmiast powróci on z operacji selekcji, być może z niezerową wartością, tak jakby wywołano metodę wybudzania selektora.
Jeśli żaden z poprzednich warunków nie zostanie spełniony, status przerwania tego wątku zostanie ustawiony.
Sprawdź to, aby uzyskać pełne zrozumienie tego samego:
http://download.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
Jeśli docelowy wątek czeka (przez wywołanie wait()
lub inne powiązane metody, które zasadniczo robią to samo, takie jak sleep()
), zostanie on przerwany, co oznacza, że przestanie czekać na to, na co czekał, i zamiast tego otrzyma InterruptedException.
wait()
Decyzja o tym, co należy zrobić w tej sytuacji, zależy od samego wątku (kodu, który wywołał ). Nie kończy automatycznie wątku.
Czasami jest używany w połączeniu z flagą zakończenia. W przypadku przerwania wątek może sprawdzić tę flagę, a następnie sam się zamknąć. Ale znowu to tylko konwencja.
Dla uzupełnienia, oprócz innych odpowiedzi, jeśli nić jest przerwana przed nim bloków na Object.wait(..)
lub Thread.sleep(..)
etc., jest to równoznaczne z tym przerwane jest bezpośrednio na blokowanie w tym sposobie , jak przedstawiono w poniższym przykładzie.
public class InterruptTest {
public static void main(String[] args) {
Thread.currentThread().interrupt();
printInterrupted(1);
Object o = new Object();
try {
synchronized (o) {
printInterrupted(2);
System.out.printf("A Time %d\n", System.currentTimeMillis());
o.wait(100);
System.out.printf("B Time %d\n", System.currentTimeMillis());
}
} catch (InterruptedException ie) {
System.out.printf("WAS interrupted\n");
}
System.out.printf("C Time %d\n", System.currentTimeMillis());
printInterrupted(3);
Thread.currentThread().interrupt();
printInterrupted(4);
try {
System.out.printf("D Time %d\n", System.currentTimeMillis());
Thread.sleep(100);
System.out.printf("E Time %d\n", System.currentTimeMillis());
} catch (InterruptedException ie) {
System.out.printf("WAS interrupted\n");
}
System.out.printf("F Time %d\n", System.currentTimeMillis());
printInterrupted(5);
try {
System.out.printf("G Time %d\n", System.currentTimeMillis());
Thread.sleep(100);
System.out.printf("H Time %d\n", System.currentTimeMillis());
} catch (InterruptedException ie) {
System.out.printf("WAS interrupted\n");
}
System.out.printf("I Time %d\n", System.currentTimeMillis());
}
static void printInterrupted(int n) {
System.out.printf("(%d) Am I interrupted? %s\n", n,
Thread.currentThread().isInterrupted() ? "Yes" : "No");
}
}
Wynik:
$ javac InterruptTest.java
$ java -classpath "." InterruptTest
(1) Am I interrupted? Yes
(2) Am I interrupted? Yes
A Time 1399207408543
WAS interrupted
C Time 1399207408543
(3) Am I interrupted? No
(4) Am I interrupted? Yes
D Time 1399207408544
WAS interrupted
F Time 1399207408544
(5) Am I interrupted? No
G Time 1399207408545
H Time 1399207408668
I Time 1399207408669
Implikacja: jeśli wykonasz pętlę w następujący sposób, a przerwanie nastąpi dokładnie w momencie, gdy kontrola odeszła Thread.sleep(..)
i okrąża pętlę, wyjątek nadal będzie występował. Dlatego całkowicie bezpiecznie jest polegać na niezawodnym zgłoszeniu wyjątku InterruptedException po przerwaniu wątku :
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException ie) {
break;
}
}
Thread.interrupt()
ustawia status / flag przerwanego wątku na true, co po sprawdzeniu za pomocą Thread.interrupted()
może pomóc w zatrzymaniu nieskończonego wątku. Zobacz http://www.yegor256.com/2015/10/20/interrupt-exception.html
Przerwanie wątku jest oparte na statusie przerwania flagi . Dla każdego wątku wartość domyślna statusu przerwania jest ustawiona na false . Ilekroć w wątku jest wywoływana metoda interrupt () , status przerwania jest ustawiany na true .
public void interrupt ()
Przerywa ten wątek.
O ile bieżący wątek się nie przerywa, co jest zawsze dozwolone, wywoływana jest metoda checkAccess tego wątku, co może spowodować zgłoszenie wyjątku SecurityException.
Jeśli ten wątek jest zablokowany w wywołaniu metod wait (), wait (long) lub wait (long, int) klasy Object, lub join (), join (long), join (long, int) , sleep (long) lub sleep (long, int), metody tej klasy, wówczas status przerwania zostanie skasowany i otrzyma wyjątek InterruptedException.
Jeśli ten wątek zostanie zablokowany podczas operacji we / wy na kanale przerywalnym, kanał zostanie zamknięty, status przerwania wątku zostanie ustawiony, a wątek otrzyma wyjątek ClosedByInterruptException.
Jeśli ten wątek zostanie zablokowany w Selektorze, zostanie ustawiony status przerwania wątku i natychmiast powróci on z operacji selekcji, być może z niezerową wartością, tak jakby wywołano metodę wybudzania selektora.
Jeśli żaden z poprzednich warunków nie zostanie spełniony, status przerwania tego wątku zostanie ustawiony.
Przerwanie wątku, który nie jest żywy, nie musi mieć żadnego skutku.
Zgłasza: wyjątek bezpieczeństwa - jeśli bieżący wątek nie może zmodyfikować tego wątku
Przerwanie jest wskazówką dla wątku, że powinien przerwać to, co robi i zrobić coś innego. Programiści decydują dokładnie, jak wątek zareaguje na przerwanie, ale jego zakończenie jest bardzo częste. Bardzo dobre referencje: https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
Metoda Thread.interrupt () ustawia wewnętrzną flagę „status przerwania”. Zazwyczaj ta flaga jest sprawdzana za pomocą metody Thread.interrupt ().
Zgodnie z konwencją każda metoda istniejąca za pośrednictwem InterruptedException musi usunąć flagę statusu przerwania.