Набросал два класса, наследующихся от
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");
}
}
}
Спасибо за комментарии к теме)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Возьмем для примера класс 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.
Вот к таким выводам я пришёл разбирая Вашу задачку.
и получил следующую картину — после выполнения этого метода interrupted() равен false посему цикл не завершается… остановить нить можно поставив в блок catch слово break.
Отсюда же видно, что исключение которое возникает во время выполнения метода sleep благополучно перехватывается и выводится стектрейс, но из-за того, что я описал выше — нить спокойно продолжает работать дальше.