прерывание () работает не так, как ожидалось (как работает прерывание?)

#java #multithreading #thread-safety #interrupt-handling

#java #многопоточность #потокобезопасность #обработка прерываний

Вопрос:

Я хочу прервать поток, но вызов interrupt() , похоже, не работает. Ниже приведен пример кода:

 public class BasicThreadrRunner {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Basic(), "thread1");
        t1.start();
        Thread t3 = new Thread(new Basic(), "thread3");
        Thread t4 = new Thread(new Basic(), "thread4");
        t3.start();
        t1.interrupt();
        t4.start();
    }
}
class Basic implements Runnable{
    public void run(){
        while(true) {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.err.println("thread: "   Thread.currentThread().getName());
                //e.printStackTrace();
            }
        }
    }
}
  

но результат выглядит так, как будто поток 1 все еще запущен. Кто-нибудь может объяснить это, а также как interrupt() работает? Спасибо!

Ответ №1:

Поток все еще выполняется просто потому, что вы перехватываете InterruptedException и продолжаете работать. interrupt() в первую очередь устанавливает флаг в Thread объекте, который вы можете проверить с помощью isInterrupted() . Это также приводит к тому, что некоторые методы — sleep() , join Object.wait() в частности — немедленно возвращаются, выдавая InterruptedException . Это также приводит к немедленному завершению некоторых операций ввода-вывода. Если вы видите распечатки из вашего catch блока, то вы можете видеть, что interrupt() это работает.

Ответ №2:

Как говорили другие, вы перехватываете прерывание, но ничего с ним не делаете. Что вам нужно сделать, так это распространить прерывание, используя логику, такую как,

 while(!Thread.currentThread().isInterrupted()){
    try{
        // do stuff
    }catch(InterruptedException e){
        Thread.currentThread().interrupt(); // propagate interrupt
    }
}
  

Использование циклической логики, такой while(true) как просто ленивое кодирование. Вместо этого опросите флаг прерванного потока, чтобы определить завершение через прерывание.

Комментарии:

1. Или вы могли бы переместить try / catch за пределы цикла. 😉

2. Да, но об этом уже упоминал @MByD, и это сохраняет эту плохую логику цикла неповрежденной. 😀

3. 1 за упоминание альтернативного подхода к <code>while ( true ) </code> p.s. Спасибо!

4. @mre InterruptedException является проверяемым исключением, если //do что-то делает с Thread.sleep, это сработает… а как насчет другого? Нужно ли мне иметь Thread.sleep обязательным?

Ответ №3:

1, в дополнение к другим ответам. Я полагаю, что неправильное представление об этом заключалось в том, что, казалось, try/catch блок завершил свою работу после Thread.sleep(1000); вызова, т. е. пытался перейти в спящий режим в течение 1000 мс, перехватывая все, что могло прервать мою попытку перехода в спящий режим.

На самом деле происходит то, что try/catch блок все еще очень активен во время сна, т. е. пытаюсь спать в течение 1000 мс, перехватываю все, что может прервать мой сон

Отсюда причина, по которой исключение перехватывается немедленно (и впоследствии), поскольку поток едва начал свой режим ожидания.