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.

Péter Török
źródło
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.

Ajay George
źródło
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.

Bert F.
źródło
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.

Piotr Findeisen
źródło
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)

Michael Ouyang
źródło