Использование Thread.currentThread().isInterrupted() с Thread.sleep()

У меня есть поток, который вызывает метод work(), который представляет собой простой цикл while(true), как показано ниже;

public void work() throws InterruptedException {
    while (true) {
        // PART A
        if (Thread.currentThread().isInterrupted()) {
            System.out.println("....run()::work::PART A::isInterrupted():" + Thread.currentThread().isInterrupted());
            Thread.sleep(2000);
        }

        // Is it possible to make the below code executable at runtime when thread is interrupted?
        // PART B
        if (Thread.currentThread().isInterrupted()) {
            System.out.println("....run()::work::PART B::isInterrupted():" + Thread.currentThread().isInterrupted());
            Thread.sleep(2000);
        }
    }
}

Я запускаю этот экземпляр потока и прерываю поток из основного через некоторое время с помощью метода Thread.sleep(). Когда я изменяю задержку, я ожидаю попадания в закомментированную часть, когда поток прерывается из основного потока, но я вижу только вывод ниже;

....run()::Work::starting
.main()::interrupting thread t
.main()::leaving
....run()::work::PART A::isInterrupted():true
....run()::Work::ERROR::INTERRUPTED

Мой простой вопрос заключается в следующем: возможно ли выполнить вторую часть (Часть B) метода work(), а если нет, то почему?

Полная демонстрация показана ниже;

public class GeneralInterrupt implements Runnable {
    public void run() {
        try {
            System.out.println("....run()::Work::starting");
            work();
            System.out.println("....run()::Work::ended");
        } catch (InterruptedException x) {
            System.out.println("....run()::Work::ERROR::INTERRUPTED");
            return;
        }
        System.out.println("....run()::Work::leaving normally");
    }

    public void work() throws InterruptedException {
        while (true) {
            // PART A
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("....run()::work::PART A::isInterrupted():" + Thread.currentThread().isInterrupted());
                Thread.sleep(2000);
            }

            // Is it possible to make the below code executable at runtime when thread is interrupted?
            // PART B
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("....run()::work::PART B::isInterrupted():" + Thread.currentThread().isInterrupted());
                Thread.sleep(2000);
            }
        }
    }

    public static void main(String[] args) {
        Thread t = new Thread(new GeneralInterrupt());
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException x) {
        }
        System.out.println(".main()::interrupting thread t");
        t.interrupt();
        System.out.println(".main()::leaving");
    }
}

Также обратите внимание, что если обе строки «Thread.sleep(2000)» удалены из частей A и B, то вывод будет

....run()::work::PART B::isInterrupted():false
....run()::work::PART B::isInterrupted():false
....run()::work::PART B::isInterrupted():false
....run()::work::PART B::isInterrupted():false
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true
....run()::work::PART A::isInterrupted():true

Может ли кто-нибудь объяснить, почему метод Thread.sleep() ведет себя таким образом внутри метода work().


person Levent Divilioglu    schedule 24.06.2015    source источник
comment
Что @Thomas пытается сказать вам, так это то, что когда происходит прерывание, вы не можете контролировать, произойдет ли это в коде, который вы написали, или в коде библиотеки, который вызывает ваш код. Если это происходит в коде библиотеки, то какая у вас гарантия, что библиотека будет обрабатывать прерывание так, как вы хотите? Хорошо спроектированная библиотечная подпрограмма остановит все, что она делает, и повторно вызовет прерывание, оставив на усмотрение вашей программы, что делать дальше. Менее хорошо спроектированная библиотека может предположить, что прерывание == выключение, и это может оставить все в плохом состоянии.   -  person Solomon Slow    schedule 24.06.2015


Ответы (3)


Согласно учебнику Oracle, прерывание потока является сигналом для поток, чтобы завершить свою текущую работу и сделать что-то еще (например, завершение):

Прерывание — это указание потоку, что он должен прекратить то, что он делает, и заняться чем-то другим. Программист должен решить, как именно поток отреагирует на прерывание, но очень часто поток завершается. Это использование подчеркивается в этом уроке.

Таким образом, обычно должно быть возможно продолжить работу после прерывания.

Согласно JavaDoc о прерываниях , это зависит от того, где поток прерывается:

Если этот поток заблокирован при вызове методов wait(), wait(long) или wait(long, int) класса Object или методов join(), join(long), join(long, int) , sleep(long) или sleep(long, int) этого класса, то его статус прерывания будет очищен и он получит InterruptedException< /эм>. (выделено мною)

Вот почему вы получаете исключение при использовании sleep(2000).

person Thomas    schedule 24.06.2015

Thread.isInterrupted() не очищает статус прерывания нить. Поэтому, когда вы вызываете sleep(), выдается InterruptedException. Вам нужно позвонить Thread.interrupted() вместо Thread.currentThread().isInterrupted().

Однако это будет означать, что часть B будет выполняться только в том случае, если во время сна после части A произошло прерывание, что, по-видимому, вам и нужно. Если вам нужно, чтобы часть B запускалась всякий раз, когда запускается часть A, поместите ее в тот же блок, а не после второго теста.

person user207421    schedule 24.06.2015

Когда вы прерываете поток, и он находится в методе sleep, sleep выдает InterruptedException. Вы не обрабатываете это исключение. Он распространяется на ваш метод run, и ваш цикл while завершается.

Вам нужно окружить свой sleep попыткой/поймать и поймать InterruptedException. Вы также должны быть уверены, что вызвали Thread.currentThread().interrupt() после его перехвата, если хотите, чтобы isInterrupted() возвращал true после исключения, так как исключение сбросит флаг прерывания. Так:

     if (Thread.currentThread().isInterrupted()) {
         System.out.println("....run()::work::PART A::isInterrupted():" 
             + Thread.currentThread().isInterrupted());
         try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
     }
person K Erlandsson    schedule 24.06.2015