Pegas
34 уровень
Гродно

Прерывания работы нити (interrupte thread).

Пост из группы Архив info.javarush.ru
3745 участников
Набросал два класса, наследующихся от Runnable. В них простая начинка ( Thread.sleep и sout). Я изучал вопрос прерывания работы нитей при помощи interrupted и isInterrupted. Почему-то прерывания не происходит, а выполнение программы зациклавается и вылетает ошибка: java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.javarush.test.myExample.example.thread.Producer.run(Producer.java:15) at java.lang.Thread.run(Thread.java:745) java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.javarush.test.myExample.example.thread.Consumer.run(Consumer.java:15) at java.lang.Thread.run(Thread.java:745) После вылета ошибки работа нитей продолжается бесконечно. Но если убрать из классов, унаследовавшихся от Runnable, вызов Thread.sleep, то программа отрабатывает нормально. В чем загвоздка, почему вылетает ошибка и почему не завершается работа программы??? Вот main: public class Solution { public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(new Producer()); Thread thread2 = new Thread(new Consumer()); thread1.start(); thread2.start(); Thread.sleep(1500); thread1.interrupt(); thread2.interrupt(); } } Первый класс: public class Producer implements Runnable { @Override public void run() { while (!Thread.interrupted()) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Producer"); } } } Второй класс: public class Consumer implements Runnable { @Override public void run() { while (!Thread.interrupted()) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Consumer"); } } } Спасибо за комментарии к теме)
Комментарии (8)
  • популярные
  • новые
  • старые
Для того, что бы оставить комментарий вы должны авторизоваться
RSeropyan25 уровень, Санкт-Петербург
3 декабря 2017, 01:44
В момент вызова метода interrupt(), каждый из потоков может находиться (грубо говоря) в одном из двух состояний — либо спать, либо пытаться проверить условие (!Thread.interrupted()).
Возьмем для примера класс Producer. В момент вызова thread1.interrupt() данный поток может:
1. Спать — при этом происходит следующее:
— Бросается исключение InterruptedException. Так как было выброшено исключение, то данный поток, несмотря на вызов метода interrupt(), не помечается как прерванный. Соответственно, условие (!Thread.interrupted()) остается равно true.
— В консоль выводится стэк трэйс.
— В консоль выводится «Producer».
— Далее идет новый виток цикла (условие = true) и так до бесконечности, так как thread1.interrupt() больше нигде не вызывается.

Чтобы в данном случае потоки корректно останавливались, в блоки catch можно добавить Thread.currentThread().interrupt() или, как посоветовали выше, использовать break
— В-первом случае сначала в консоль будет выведено «Producer», а потом поток остановится.
— Во-втором случае — поток просто остановится.

2. Пытаться проверить условие (!Thread.interrupted()) — тут все понятно: thread1.interrupt() помечает поток как прерванный, на новом витке цикла условие в скобках = false и поток останавливается. В вашем случае, если вы убираете из try команду Thread.sleep, вы «ловите» командой interrupt() поток именно в этом состоянии — не когда он спит, а когда пытается проверить не был ли он прерван. При наличие Thread.sleep в большинстве случаев вы будете «ловить» поток в состоянии сна и все будет развиваться по сценарию варианта 1.
Grif11 уровень
22 июня 2016, 02:51
:) Можно правда и так:
public class Producer implements Runnable {
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                Thread.sleep(100);
                System.out.println("Producer");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Pegas34 уровень, Гродно
22 июня 2016, 20:34
Вот это, на мой взгляд, наиболее работоспособный и применимый в практике вариант. Блок while нужно помещать в try-catch и все будет ок. А вместо e.printStackTrace(); можно вывести какое-нибудь сообщение(например,«работа прервана»), чтобы было понятна логика работы программы. Спасибо за помощь, Grif , плюс в профиль:)
Grif11 уровень
22 июня 2016, 20:58
:) Хорошему человеку помочь не жалко :)
Тем более тезке :) И тем более, что у нас, если Ваша информация верна в профиле, разница в годах на круглое число… очень символично:)
Grif11 уровень
22 июня 2016, 02:31
Я немного неверно написал
после выполнения этого метода interrupted() равен false посему цикл не завершается… остановить нить можно поставив в блок catch слово break.
Ведь исключение возникает и перехватывается только в случае прерывания метода sleep а это значит, что для надежности лучше предусмотреть дополнительное прерывание нити, надеяться только на interrupted в чистом виде неполучается.
Grif11 уровень
22 июня 2016, 02:25
Т.е. существует вероятность, что thread.interrupt() будет вызвано после блока try/catch до проверки в цикле while (!Thread.interrupted()) но она видимо очень мала.

Вот к таким выводам я пришёл разбирая Вашу задачку.
Grif11 уровень
22 июня 2016, 02:20
Метод sleep является нативным, т.е. он реализован на другом языке не на Java поэтому детальное его исследование слегка затруднено… но я пошёл немного другим путём, а именно:
System.out.println("Producer before "+Thread.interrupted());
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Producer after "+Thread.interrupted());

и получил следующую картину — после выполнения этого метода interrupted() равен false посему цикл не завершается… остановить нить можно поставив в блок catch слово break.

Отсюда же видно, что исключение которое возникает во время выполнения метода sleep благополучно перехватывается и выводится стектрейс, но из-за того, что я описал выше — нить спокойно продолжает работать дальше.
Pegas34 уровень, Гродно
22 июня 2016, 20:18
Grif респект, с установкой break в try-catch — это зачетно придумано, на первый взгляд отлично работает. Осталось понять есть ли в данном случае подводные камни.