Do czego służy java.lang.Thread.interrupt ()?


Odpowiedzi:


250

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()
  • Większość java.util.concurrentstruktur
  • Java NIO (ale nie java.io) i NIE używa InterruptedExceptionzamiast 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.


22
Zauważ, że metody takie jak sen lub czekaj wykonują tego rodzaju odpytywanie i same zgłaszają wyjątek InterruptedException.
Thilo

1
Jeśli używasz przerywanych operacji wejścia / wyjścia, efekt nie będzie tak łagodny. Zazwyczaj dostaniesz uszkodzenie pliku.
Marko Topolnik,

jeśli wspominasz o Thread.interrupt, wydaje się, że należy wspomnieć, że istnieje również flaga Thread.isInterrupted, która nie usuwa flagi, co sprawia, że ​​jest zwykle bardziej odpowiednia dla twórców aplikacji.
Nathan Hughes

67

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


To jest częściowe wyjaśnienie. Przerywa także metody przerywalne.
Markiz Lorne

@EJP To pytanie dotyczy tego, czym jest metoda Thread.interrupt () i jak działa. Myślę, że niezależnie od tego, co opublikowałem, z linkiem, odpowiada na pytania. Nadal nie rozumiem, czego chcesz?
YoK

Chciałbym, abyś poprawił swoje częściowo niepoprawne stwierdzenie, że zostało ono zaimplementowane przez flagę. To tylko część historii. Wydaje mi się to całkiem jasne.
Markiz Lorne

@EJP Thanks. Teraz rozumiem, co mówiłeś. Zaktualizowałem swoją odpowiedź i dodałem dokument API dla metody. Obejmuje to część metod przerywalnych, której brakowało w mojej odpowiedzi. Mam nadzieję, że moja odpowiedź wygląda teraz kompletnie :).
YoK

13

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.


9 lat, ponadczasowa odpowiedź! +1
snr

10

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;
    }
}


4

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 .

  1. Jeśli status przerwania = true (interrupt () już wywołany w wątku), ten konkretny wątek nie może przejść w tryb uśpienia. W przypadku wywołania uśpienia w tym wątku zostaje przerwany wyjątek. Po wyrzuceniu wyjątku ponownie flaga jest ustawiona na false.
  2. Jeśli wątek już śpi i wywołane jest przerwanie () , wątek wyjdzie ze stanu uśpienia i wyrzuci przerwany wyjątek.

1

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



1

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.