Остановить все потоки java

Different Ways to Kill a Thread in Java

There is no official method to kill a thread in Java. Stopping a thread is entirely managed by the JVM. Although Java provides several ways to manage the thread lifecycle such as a start(), sleep(), stop() (deprecated in Java 1.1), etc. but does not provide any method to kill a thread and free the resources cleanly.

Oracle specified the reason for deprecating the stop() method as It is inherently unsafe. Stopping a thread causes it to unlock all its locked monitors.

1. Two Ways to Kill a Thread

Effectively, we can only signal the thread to stop itself and let the thread clean up the resources and terminate itself. In Java, we can send a signal to a thread in two ways:

  • By periodically checking a boolean flag
  • By interrupting the thread using Thread.interrupt() method

Let us learn about both methods:

In this method, we check a boolean flag periodically, or after every step in the task. Initially, the flag is set to false. To stop the thread, set the flag to true. Inside the thread, when the code checks the flag’s value to true, it destroys itself gracefully and returns.

Note that in this design, generally, there are two threads. One thread sets the flag value to true, and another thread checks the flag value. To ensure that both threads see the same value all the time, we must make the flag variable volatile. Or we can use AtomicBoolean class that supports atomic operations on an underlying volatile boolean variable.

public class CustomTask implements Runnable < private volatile boolean flag = false; private Thread worker; public void start() < worker = new Thread(this); worker.start(); >public void stop() < flag = true; >@Override public void run() < while (!flag) < try < Thread.sleep(500); System.out.println(Thread.currentThread().getName() + " Running. "); >catch (InterruptedException e) < Thread.currentThread().interrupt(); System.out.println("Thread was interrupted," + e.getMessage()); >> System.out.println(Thread.currentThread().getName() + " Stopped"); return; > >

Let us test this design by creating two threads and stopping them.

CustomTask task1 = new CustomTask(); CustomTask task2 = new CustomTask(); task1.start(); task2.start(); try < Thread.sleep(1000); task1.stop(); task2.stop(); >catch (InterruptedException e)
Thread-0 Running. Thread-1 Running. Thread-1 Running. Thread-0 Running. Thread-1 Stopped Thread-0 Stopped

3. By Interrupting the Thread

Читайте также:  Бинарный метод поиск java

This method is also very similar to the previous approach of using a flag. The only difference is that we will interrupt the thread instead of setting the flag to false.

So inside the thread, we will keep checking the thread’s interrupt status, and when the thread is interrupted, we will stop the thread gracefully. To check the status of the interrupted thread, we can use the Thread.isInterrupted() method. It returns either true or false based on the thread’s interrupt status.

public class CustomTaskV2 implements Runnable < private Thread worker; public void start() < worker = new Thread(this); worker.start(); >public void interrupt() < worker.interrupt(); >@Override public void run() < while (!Thread.currentThread().isInterrupted()) < try < Thread.sleep(500); System.out.println(Thread.currentThread().getName() + " Running. "); >catch (InterruptedException e) < Thread.currentThread().interrupt(); System.out.println("Thread was interrupted with reason : " + e.getMessage()); >> System.out.println(Thread.currentThread().getName() + " Stopped"); return; > >

Interestingly, the code to test this design is similar to the previous one. Only the method call to thread.interrupt() is additional.

CustomTaskV2 task1 = new CustomTaskV2(); CustomTaskV2 task2 = new CustomTaskV2(); task1.start(); task2.start(); try < Thread.sleep(1100);isInterrupted task1.interrupt(); task2.interrupt(); >catch (InterruptedException e)
Thread-0 Running. Thread-1 Running. Thread-1 Running. Thread-0 Running. Thread was interrupted with reason : sleep interrupted Thread was interrupted with reason : sleep interrupted Thread-0 Stopped Thread-1 Stopped

This tutorial taught us to kill a running thread in Java using custom solutions. Even though the boolean flag solution is very good, it may not give the desired result for long-running tasks where the thread is waiting most of the time.

Sending an interrupt is a much better approach to stop a long-waiting thread.

Источник

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 .

Источник

Остановить все потоки 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()); >

Источник

Оцените статью