#java #multithreading #thread-safety
#java #многопоточность #потокобезопасность
Вопрос:
В документации Java нет ясности по этому вопросу. Что произойдет, если вы вызовете interrupt в потоке перед вызовом Thread.sleep():
//interrupt reaches Thread here
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
return;
}
Будет ли вызвано исключение InterruptedException?
Пожалуйста, укажите на соответствующую документацию.
Ответ №1:
Да, это вызовет исключение. Согласно javadoc для Thread.sleep, метод:
Выдает: Исключение InterruptedException — если какой-либо поток прервал текущий поток. Статус прерывания текущего потока очищается при возникновении этого исключения.
‘has’ в данном случае является неформальным способом обозначения состояния прерывания. Жаль, что это неофициально — если где-то спецификация должна быть точной и недвусмысленной, что ж, она есть везде, но прежде всего это примитивы обработки потоков.
Способ, которым механизм состояния прерывания работает в общем, заключается в том, что если поток получает прерывание, в то время как он не прерываем (потому что он запущен), то прерывание, по сути, заставлено ждать, пока поток не будет прерван, и в этот момент он переходит в состояние, вызывающее исключение InterruptedException . Это пример такого механизма.
Ответ №2:
Поток может быть прерван в любой момент времени, но это не будет иметь никакого эффекта до тех пор, пока этот поток специально не проверит свое прерванное состояние с помощью Thread.currentThread().isInterrupted()
или когда он достигнет, или уже заблокирован вызовом Thread.sleep(long)
, Object.wait(long)
или другими стандартными методами JDK, которые выдают, InterruptedException
например, в java.nio
пакете. Статус прерывания потока сбрасывается при обнаружении InterruptedException
или при явном вызове Thread.interrupted()
(см. Документацию по этому неуловимому методу).
В этой статье для JavaSpecialists должно быть немного больше объяснений о том, как работают прерывания потока и как с ними правильно обращаться.
Комментарии:
1. «Статус прерывания потока сбрасывается при обнаружении исключения InterruptedException» — Не совсем. Согласно javadoc, статус сбрасывается при выбросе исключения, а не при его перехвате. (И это действительно означает, что перед
throw
инструкцией … или, в данном случае, эквивалент машинного кодаthrow
.)2. Да, это верно, но, конечно, вы на самом деле не сможете проверить это или сделать что-либо еще, пока это не будет перехвачено. Я предполагаю, что длинный способ сказать это так: «Статус прерывания потока уже будет сброшен к тому времени, когда вы поймаете
InterruptedException
»3. Этот ответ полностью не соответствует исходному вопросу, не уверен, почему OP принял это. Вопрос в том, приведет ли вызов,
Thread.sleep()
когда флаг прерывания уже установлен, к запуску методаInterruptedException
, и это вообще не пытается ответить на этот вопрос.4. Я думаю, вы можете привести лошадь к воде, но вы не можете заставить ее пить. Я предоставил более чем достаточно информации для OP, чтобы выработать ответ на его собственный вопрос. В случае, если вы этого не поняли, ответ — Да.
5. @BoffinbraiN, иногда причина, по которой люди задают здесь вопросы, заключается не в том, что недостаточно информации, а в том, что доступно так много информации, что она затушевывает фактический ответ на простой вопрос. Иногда ответ на такой вопрос, содержащий слишком много информации, способствует информационной перегрузке и заставляет пользователя задуматься: «итак, если этот абзац ответа предположительно содержит ответ, то почему они просто не сказали «да» или «нет»?» Итак, спасибо, что добавили продолжение с фактическим «да», потому что ваш подробный ответ все еще оставлял немного неясным.
Ответ №3:
Вы можете использовать следующий класс для проверки поведения. В этом случае цикл не прерывается, и поток останавливается, когда переходит в спящий режим.
открытый класс TestInterrupt{
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
public void run(){
System.out.println("hello");
try {
for (int i = 0 ; i < 1000000; i ){
System.out.print(".");
}
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("interrupted");
e.printStackTrace();
}
}
};
t.start();
Thread.sleep(100);
System.out.println("about to interrupt.");
t.interrupt();
}
}
Комментарии:
1. Я попробовал вариант этой программы, и она выдала исключение InterruptedException, подтвердив, что ответы Боффина и Тома верны.
2. ДА. Он выдает исключение, но вопрос в том, когда? В приведенном выше случае исключение не генерируется до тех пор, пока не будет вызван режим ожидания.
3. Да, вы правы. Но в этом и был весь смысл: будет ли sleep() выдавать исключение, если прерывание произошло до вызова? И ответ: да!
Ответ №4:
Документы InterruptedException, похоже, предполагают, что оно может быть прервано в другое время
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/InterruptedException.html
Вызывается, когда поток ожидает, переходит в спящий режим или иным образом приостановлен на длительное время, а другой поток прерывает его, используя метод прерывания в классе Thread
Кроме того, поскольку это проверяемое исключение, оно будет выдаваться только методами, которые его объявляют. Смотрите
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#interrupt()