Java работа с прерываниями
почему мы еще раз проверяем отработала ли первая нить , если вторая должна запуститься после завершения первой нити ?
Как посмотреть все статьи данного автора? А то написано «Давай вспомним пример из предыдущей лекции» а где эту лекцию найти хз
Зачем проверка isInterrupted в while (!current.isInterrupted()) ? Если использовать while (true), то в Thread.sleep все равно будет проверка и выброс InterruptedException.
Цитата: «Давай вернемся к примеру с часами, который был в лекции основного курса.» Что за «основной курс»?
Конечно я и сам не оратор, но смотреть этот ролик невозможно : ээ, эмм, вот, так вот, вот — тот еще мямля. Простите но это просто не качественный контент разжиженый водичкой . Еще с красным маркером , едва видным, по белому холсту, ужас.
Дело в том, что прямой вызов метода run() не имеет отношения к многопоточности. В этом случае программа будет выполнена в главном потоке — том, в котором выполняется метод main(). Он просто последовательно выведет 10 строк на консоль и все. Никакие 10 потоков не запустятся. Почему же тогда метод getName() выдает 10 разных значений? Откуда 10 разных имён потоков, если всё выполняется в главном потоке? Кто-то может объяснить? Попробовал переписать код с имплементацией Runnable вместо наследования Thread:
public class MainRunnable < public static void main(String[] args) < for (int i = 0; i < 10; i++) < Thread thread = new Thread(new mulithreading.MyFirstThread2()); thread.run(); >> > class MyFirstThread2 implements Runnable < @Override public void run() < System.out.println("Выполнен поток " + Thread.currentThread().getName()); >>
Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main Выполнен поток main
ВНИМАНИЕ, ВОПРОС! Зачем в методе run в цикле while с условием !current.isInterrupted() при выкидывании InterruptedException мы в блоке catch дополнительно завершаем цикл с помощью break, если в условии цикла у нас уже есть проверка на isInterrupted? По-моему что-то одно следует убрать, либо условие из цикла и оставить только while (true), либо break при обработке исключения.
public class Clock extends Thread < public static void main(String[] args) throws InterruptedException < Clock clock = new Clock(); clock.start(); Thread.sleep(10000); clock.interrupt(); >public void run() < Thread current = Thread.currentThread(); while (!current.isInterrupted()) < try < Thread.sleep(1000); >catch (InterruptedException e) < System.out.println("Работа потока была прервана"); break; >System.out.println("Tik"); > > >
Интересно, если есть 4 потока, можно ли сделать так, чтобы: — 1-й поток ждал пока не заверлится 3-й; — 2-й поток ждал пока не заверлится 4-й; и все это параллельно. — 3-й потом работал параллельно 4-му; — после завершение 3-го и 4-го потоков 1-й и 2-й потоки работали также параллельно (при условии что 3-й и 4-й потоки завершились одновременно). Как будет выглядеть код? Метод join(); как я понял, регулирует очередность потоков, но не позволяет «создавать несколько параллельных очередностей» или я не прав? Поясните, пожалуйста, знатоки 🙂
Java работа с прерываниями
Примеры потоков ранее представляли поток как последовательный набор операций. После выполнения последней операции завершался и поток. Однако нередко имеет место и другая организация потока в виде бесконечного цикла. Например, поток сервера в бесконечном цикле прослушивает определенный порт на предмет получения данных. И в этом случае мы также можем предусмотреть механизм завершения потока.
Завершение потока
Распространенный способ завершения потока представляет опрос логической переменной. И если она равна, например, false, то поток завершает бесконечный цикл и заканчивает свое выполнение.
Определим следующий класс потока:
class MyThread implements Runnable < private boolean isActive; void disable()< isActive=false; >MyThread() < isActive = true; >public void run() < System.out.printf("%s started. \n", Thread.currentThread().getName()); int counter=1; // счетчик циклов while(isActive)< System.out.println("Loop " + counter++); try< Thread.sleep(400); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >> System.out.printf("%s finished. \n", Thread.currentThread().getName()); > >
Переменная isActive указывает на активность потока. С помощью метода disable() мы можем сбросить состояние этой переменной.
Теперь используем этот класс:
public static void main(String[] args) < System.out.println("Main thread started. "); MyThread myThread = new MyThread(); new Thread(myThread,"MyThread").start(); try< Thread.sleep(1100); myThread.disable(); Thread.sleep(1000); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >System.out.println("Main thread finished. "); >
Итак, вначале запускается дочерний поток: new Thread(myThread,»MyThread»).start() . Затем на 1100 миллисекунд останавливаем Main thread и потом вызываем метод myThread.disable() , который переключает в потоке флаг isActive. И дочерний поток завершается.
Метод interrupt
Еще один способ вызова завершения или прерывания потока представляет метод interrupt() . Вызов этого метода устанавливает у потока статус, что он прерван. Сам метод возвращает true, если поток может быть прерван, в ином случае возвращается false.
При этом сам вызов этого метода НЕ завершает поток, он только устанавливает статус: в частности, метод isInterrupted() класса Thread будет возвращать значение true. Мы можем проверить значение возвращаемое данным методом и прозвести некоторые действия. Например:
class JThread extends Thread < JThread(String name)< super(name); >public void run() < System.out.printf("%s started. \n", Thread.currentThread().getName()); int counter=1; // счетчик циклов while(!isInterrupted())< System.out.println("Loop " + counter++); >System.out.printf("%s finished. \n", Thread.currentThread().getName()); > > public class Program < public static void main(String[] args) < System.out.println("Main thread started. "); JThread t = new JThread("JThread"); t.start(); try< Thread.sleep(150); t.interrupt(); Thread.sleep(150); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >System.out.println("Main thread finished. "); > >
В классе, который унаследован от Thread, мы можем получить статус текущего потока с помощью метода isInterrupted() . И пока этот метод возвращает false, мы можем выполнять цикл. А после того, как будет вызван метод interrupt, isInterrupted() возвратит true, и соответственно произойдет выход из цикла.
Возможный консольный вывод:
Main thread started. JThread started. Loop 1 Loop 2 Loop 3 Loop 4 JThread finished. Main thread finished.
Если основная функциональность заключена в классе, который реализует интерфейс Runnable, то там можно проверять статус потока с помощью метода Thread.currentThread().isInterrupted() :
class MyThread implements Runnable < public void run()< System.out.printf("%s started. \n", Thread.currentThread().getName()); int counter=1; // счетчик циклов while(!Thread.currentThread().isInterrupted())< System.out.println("Loop " + counter++); >System.out.printf("%s finished. \n", Thread.currentThread().getName()); > > public class Program < public static void main(String[] args) < System.out.println("Main thread started. "); MyThread myThread = new MyThread(); Thread t = new Thread(myThread,"MyThread"); t.start(); try< Thread.sleep(150); t.interrupt(); Thread.sleep(150); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >System.out.println("Main thread finished. "); > >
Однако при получении статуса потока с помощью метода isInterrupted() следует учитывать, что если мы обрабатываем в цикле исключение InterruptedException в блоке catch, то при перехвате исключения статус потока автоматически сбрасывается, и после этого isInterrupted будет возвращать false.
Например, добавим в цикл потока задержку с помощью метода sleep:
public void run() < System.out.printf("%s started. \n", Thread.currentThread().getName()); int counter=1; // счетчик циклов while(!isInterrupted())< System.out.println("Loop " + counter++); try< Thread.sleep(100); >catch(InterruptedException e) < System.out.println(getName() + " has been interrupted"); System.out.println(isInterrupted()); // false interrupt(); // повторно сбрасываем состояние >> System.out.printf("%s finished. \n", Thread.currentThread().getName()); >
Когда поток вызовет метод interrupt, метод sleep сгенерирует исключение InterruptedException, и управление перейдет к блоку catch. Но если мы проверим статус потока, то увидим, что метод isInterrupted возвращает false. Как вариант, в этом случае мы можем повторно прервать текущий поток, опять же вызвав метод interrupt(). Тогда при новой итерации цикла while метода isInterrupted возвратит true, и поизойдет выход из цикла.
Либо мы можем сразу же в блоке catch выйти из цикла с помощью break:
while(!isInterrupted()) < System.out.println("Loop " + counter++); try< Thread.sleep(100); >catch(InterruptedException e) < System.out.println(getName() + " has been interrupted"); break; // выход из цикла >>
Если бесконечный цикл помещен в конструкцию try. catch, то достаточно обработать InterruptedException:
public void run() < System.out.printf("%s started. \n", Thread.currentThread().getName()); int counter=1; // счетчик циклов try< while(!isInterrupted())< System.out.println("Loop " + counter++); Thread.sleep(100); >> catch(InterruptedException e) < System.out.println(getName() + " has been interrupted"); >System.out.printf("%s finished. \n", Thread.currentThread().getName()); >
Interrupts
An interrupt is an indication to a thread that it should stop what it is doing and do something else. It’s up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate. This is the usage emphasized in this lesson.
A thread sends an interrupt by invoking interrupt on the Thread object for the thread to be interrupted. For the interrupt mechanism to work correctly, the interrupted thread must support its own interruption.
Supporting Interruption
How does a thread support its own interruption? This depends on what it’s currently doing. If the thread is frequently invoking methods that throw InterruptedException , it simply returns from the run method after it catches that exception. For example, suppose the central message loop in the SleepMessages example were in the run method of a thread’s Runnable object. Then it might be modified as follows to support interrupts:
for (int i = 0; i < importantInfo.length; i++) < // Pause for 4 seconds try < Thread.sleep(4000); >catch (InterruptedException e) < // We've been interrupted: no more messages. return; >// Print a message System.out.println(importantInfo[i]); >
Many methods that throw InterruptedException , such as sleep , are designed to cancel their current operation and return immediately when an interrupt is received.
What if a thread goes a long time without invoking a method that throws InterruptedException ? Then it must periodically invoke Thread.interrupted , which returns true if an interrupt has been received. For example:
In this simple example, the code simply tests for the interrupt and exits the thread if one has been received. In more complex applications, it might make more sense to throw an InterruptedException :
This allows interrupt handling code to be centralized in a catch clause.
The Interrupt Status Flag
The interrupt mechanism is implemented using an internal flag known as the interrupt status. Invoking Thread.interrupt sets this flag. When a thread checks for an interrupt by invoking the static method Thread.interrupted , interrupt status is cleared. The non-static isInterrupted method, which is used by one thread to query the interrupt status of another, does not change the interrupt status flag.
By convention, any method that exits by throwing an InterruptedException clears interrupt status when it does so. However, it’s always possible that interrupt status will immediately be set again, by another thread invoking interrupt .