Вызывающий Thread.sleep() с установленным статусом * прервано*?

#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()