В первом случае («i»), да, спящий поток будет вытолкнут из своего вызова Thread#sleep()
посредством выбрасывания InterruptedException
. На этом этапе флаг состояния потока представлен Thread#isInterrupted()
будет очищен; вызов Thread#isInterrupted()
вернет false. Поскольку InterruptedException
находится в полете, сообщение было отправлено всем транзитивным вызывающим абонентам.
Затем вызывающая сторона несет ответственность за перехват этого исключения и выполнение одного из двух действий:
- либо выйти из текущего потока, либо
- вызовите
Thread#interrupt()
в текущий поток (то есть Thread.currentThread().interrupt()
)
Когда вы говорите, что поток «t1» «все еще находится в состоянии сна, ожидания или присоединения», единственный способ, которым это может быть после его первоначального вызова Thread#sleep()
, завершенного через InterruptedException
, — это если он поймал исключение, проигнорировал его и вызвал снова использовать какой-либо метод блокировки, например Thread.sleep()
, прежде чем поток "t2" сможет прервать его во второй раз.
Если поток "t2" снова прервет поток "t1", в то время как "t1" в настоящее время заблокирован вызовом прерываемого метода, вызов "t1" снова завершится с InterruptedException
. В противном случае будет установлен флаг прерывания потока для последующего обнаружения.
Каждый раз, когда вызывается Thread#interrupt()
, статус прерывания этого целевого потока будет установлен на «истина», что означает, что поток был прерван с момента последнего сброса его статуса прерывания. В следующий раз, когда прерванный поток попытается выполнить блокирующий вызов прерываемого метода, статус прерывания потока будет очищен, и метод выдаст InterruptedException
.
Обратите внимание, что сброс статуса прерывания подобным образом не приводит к потере информации, если сразу после сброса выдается InterruptedException
. Выброшенный InterruptedException
лучше всего интерпретировать как «У этого потока был установлен статус прерывания в какой-то момент ранее, и теперь вы обязаны реагировать и, как правило, предупреждать последующие вызывающие объекты о предполагаемом прерывании». Вы достигаете последней цели, вызывая Thread#interrupt()
после перехвата InterruptedException
, восстанавливая статус прерывания для просмотра другими.
Более подробное описание этого протокола см. в книге Java Concurrency in Practice.
24.11.2011