#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 мс, перехватываю все, что может прервать мой сон
Отсюда причина, по которой исключение перехватывается немедленно (и впоследствии), поскольку поток едва начал свой режим ожидания.