Навіщо викликати Thread.currentThread.interrupt () у блоці запису InterruptException?


Відповіді:


160

Це робиться для утримання держави .

Коли ви ловите InterruptExceptionта проковтуєте його, ви по суті заважаєте будь-яким методам / групам ниток більш високого рівня помітити переривання. Що може спричинити проблеми.

Зателефонувавши Thread.currentThread().interrupt(), ви встановлюєте прапор переривання потоку, тому обробники переривань вищого рівня помітять його та можуть належним чином обробити його.

Конкурс Java на практиці обговорює це більш докладно в Розділі 7.1.3: Відповідь на переривання . Його правило:

Тільки код, який реалізує політику переривання потоку, може проковтнути запит переривання. Завдання загального призначення та код бібліотеки ніколи не повинні ковтати запити на переривання.


15
У документації зазначається, що "За умовами, будь-який метод, який виходить із закидання InterruptedException статусу переривання, коли він це робить. Я думаю, що це робить відповідь зрозумілішою з точки зору того, чому потрібно зберегти статус переривання."
Stelios Adamantidis

Також варто зазначити, що interrupt()виклик - це єдиний спосіб встановити перерваний прапор, коли ви отримаєте повідомлення про цей стан через інший "механізм доставки" - InterruptedExceptionі бажаєте чи не можете його повторно кинути.
сево

67

Я думаю, що цей зразок коду робить речі трохи зрозумілими. Клас, який виконує роботу:

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

Основний клас:

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

    }

Спробуйте зателефонувати без перерви, не повертаючи статус.


13
тому висновок є ??
Скотт 混合 理论

3
Дякую. Я бачу, що ви маєте на увазі зараз: repl.it/@djangofan/InterruptedThreadExample
djangofan

20

Примітка:

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

Як зупинити потік, який довго чекає (наприклад, для введення)?

Щоб ця методика працювала, дуже важливо, щоб будь-який метод, який сприймає виняток переривання і не готовий з цим боротися, негайно підтверджує виняток. Ми кажемо, що це повторно, а не повторно, тому що не завжди можливо повторно скинути виняток. Якщо метод, який ловить InterruptException, не оголошений, щоб викинути цей (перевірений) виняток, він повинен "перезавантажити себе" з наступним закликом:

Thread.currentThread().interrupt();

Це гарантує, що Нитка перейме наново перерваний InterxException, як тільки зможе.


2

Я вважав би це поганою практикою або хоча б трохи ризикованою. Зазвичай методи вищого рівня не виконують операцій блокування, і вони ніколи не побачатьInterruptedException там . Якщо ви маскуєте його в кожному місці, коли ви виконуєте операцію з перериванням, ви її ніколи не отримаєте.

Єдине обґрунтування Thread.currentThread.interrupt()та не викликає будь-якого іншого винятку чи сигналізації запиту на переривання будь-яким іншим способом (наприклад, встановлення interruptedлокальної змінної змінної у головному циклі потоку) - це ситуація, коли ви дійсно нічого не можете зробити за винятком, як у finallyблоках.

Дивіться відповідь Петера Тьорка, якщо ви хочете краще зрозуміти наслідки Thread.currentThread.interrupt()дзвінка.


0

Зверніться до java doc

Якщо цей потік заблокований у виклику wait (), join (), sleep (long), то його стан переривання буде очищено, і він отримає InterruptException.

Якщо цей потік заблокований в операції вводу / виводу, буде встановлено статус переривання потоку, і потік отримає ClosedByInterruptException.

Якщо цей потік заблокований у селекторі, то буде встановлено стан переривання потоку і він негайно повернеться з операції вибору.

Якщо жодна з попередніх умов не виконується, буде встановлено статус переривання цього потоку.

Отже, якщо ви змінили метод sleepBabySleep () в @Ajay George Answer to I / O Operation або просто систематизації, вам не доведеться повертати стан, щоб зупинити програму. (До речі, вони навіть не кидають InterruptException)

Так, як сказав @ Péter Török => Це робиться для збереження стану. (Зокрема, для методу, який викине InterruptException)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.