Po co wywoływać Thread.currentThread.interrupt () w bloku catch InterruptException?


Odpowiedzi:


160

Ma to na celu utrzymanie stanu .

Kiedy złapiesz go InterruptExceptioni połkniesz, zasadniczo zapobiegniesz zauważeniu przerwania przez metody wyższego poziomu / grupy wątków. Co może powodować problemy.

Wywołując Thread.currentThread().interrupt(), ustawiasz flagę przerwania wątku, aby programy obsługi przerwań wyższego poziomu zauważyły ​​to i mogły odpowiednio obsłużyć.

Współbieżność języka Java w praktyce omówiono bardziej szczegółowo w rozdziale 7.1.3: Reagowanie na przerwanie . Jego zasada brzmi:

Tylko kod, który implementuje politykę przerywania wątku, może połknąć żądanie przerwania. Zadanie ogólnego przeznaczenia i kod biblioteki nigdy nie powinny połykać żądań przerwania.


15
W dokumentacji jest powiedziane, że „Zgodnie z konwencją, każda metoda, która wychodzi przez rzucenie InterruptedException kasowania statusu przerwania, kiedy to robi. Myślę, że to wyjaśnia, dlaczego należy zachować stan przerwania.
— Stelios Adamantidis

Warto również zauważyć, że interrupt()połączenie jest jedynym sposobem na ustawienie flagi przerwania, gdy otrzymałeś powiadomienie o tym stanie za pośrednictwem innego „mechanizmu dostarczania” - InterruptedExceptioni chcesz lub nie możesz go ponownie wysłać.
— sevo

67

Myślę, że ten przykład kodu wyjaśnia sprawę. Klasa, która wykonuje zadanie:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

Główna klasa:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

Spróbuj wywołać przerwanie bez przywracania stanu.


13
więc wniosek jest taki?
— Scott 混合 理论

3
Dzięki. Teraz rozumiem, co masz na myśli: repl.it/@djangofan/InterruptedThreadExample
— djangofan

20

Uwaga:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Jak zatrzymać wątek, który czeka przez długi czas (np. Na dane wejściowe)?

Aby ta technika zadziałała, ważne jest, aby każda metoda, która wyłapuje wyjątek przerwania i nie jest przygotowana do jego rozwiązania, natychmiast ponownie potwierdza wyjątek. Mówimy raczej o ponownym potwierdzeniu niż o ponownym zgłoszeniu, ponieważ nie zawsze jest możliwe ponowne zgłoszenie wyjątku. Jeśli metoda przechwytująca InterruptedException nie jest zadeklarowana do zgłaszania tego (zaznaczonego) wyjątku, powinna „przerwać się ponownie” z następującą inkantacją:

Thread.currentThread().interrupt();

Gwarantuje to, że Thread ponownie wywoła InterruptedException, gdy tylko będzie to możliwe.


2

Uznałbym to za złą praktykę lub przynajmniej trochę ryzykowną. Zwykle metody wyższego poziomu nie wykonują operacji blokujących i nigdy ich InterruptedExceptiontam nie zobaczą . Jeśli zamaskujesz to w każdym miejscu, w którym wykonujesz operację przerywaną, nigdy jej nie uzyskasz.

Jedynym uzasadnieniem dla Thread.currentThread.interrupt()i nie zgłaszania żadnego innego wyjątku lub sygnalizowania żądania przerwania w jakikolwiek inny sposób (np. Ustawienie interruptedzmiennej lokalnej w głównej pętli wątku) jest sytuacja, w której naprawdę nie można nic zrobić z wyjątkiem, jak w finallyblokach.

Zobacz odpowiedź Pétera Töröka, jeśli chcesz lepiej zrozumieć konsekwencje Thread.currentThread.interrupt()rozmowy.


0

Zapoznaj się z dokumentacją java

Jeśli ten wątek zostanie zablokowany w wywołaniu funkcji wait (), join (), sleep (long), wówczas stan jego przerwania zostanie wyczyszczony i otrzyma wyjątek InterruptedException.

Jeśli ten wątek jest zablokowany w operacji we / wy, stan przerwania wątku zostanie ustawiony, a wątek otrzyma ClosedByInterruptException.

Jeśli ten wątek jest zablokowany w selektorze, wówczas stan przerwania wątku zostanie ustawiony i powróci on natychmiast po operacji wyboru.

Jeśli żaden z poprzednich warunków nie jest spełniony, stan przerwania tego wątku zostanie ustawiony.

Tak więc, jeśli zmienisz metodę sleepBabySleep () w @Ajay George Answer to I / O operation lub po prostu sysout, nie musisz ponownie ustawiać statusu, aby zatrzymać program. (BTW, nawet nie rzucają InterruptedException)

Tak jak powiedział @ Péter Török => Ma to na celu utrzymanie stanu. (Szczególnie w przypadku metody, która spowoduje zgłoszenie InterruptedException)

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.