JAVA concurrent programming 9_correct thread closure, java concurrent thread
Java does not provide any security mechanisms to terminate threads. Although methods such as Thread. stop and suspend provide such mechanisms, they have serious defects and should be avoided.
It provides interrupt, a collaboration mechanism that allows one thread to terminate the current work of another thread.
A collaboration mechanism is to set a "canceled request (Cancellation Requested)" flag, which is regularly viewed by tasks.
"Canceled" flag
private volatile boolean cancelled;public void run() { while (!cancelled) { doSomething(); }}public void cancel() { cancelled = true;}
In this way, the polling flag is used to determine whether to continue the task. If the cancel flag is not called, the task will continue to run. Volatile ensures the visibility of the logo so that the process can work reliably.
The cancelling mechanism of Cancel can Cancel the task, but it takes some time to exit. In extreme cases, when a task calls a blocking method, such as sleep/wait /... The task may never check the cancellation flag, so it will never end.
public class CloseThread extends Thread { private volatile boolean cancelled; public void run() { while (!cancelled) { doSomething(); } } private void doSomething() { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } public void cancel() { cancelled = true; } public static void main(String[] args) { final CloseThread closeThread = new CloseThread(); closeThread.start(); Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { closeThread.cancel(); System.out.println("closeThread isAlive --" + closeThread.isAlive()); } }, 2000); }}
Print as follows:
CloseThread isAlive-true
The polling status flag in the run method. When canceled is set to false, the task continues to be executed. After 2 seconds, the cancel method is called to set the canceled flag to true.
It can be seen that when the run method takes a long time, it can be polling once every 10 s, that is, it takes some time to exit the task. At this time, the thread cannot be closed during the call, the thread can be closed after 10 s. In extreme cases, when a blocking method is encountered, the thread will never be shut down.
Therefore, there is a problem with the flag setting method. The custom cancellation mechanism cannot interact well with the blocking method.
Use interrupt to close the thread
Generally, interruption is the most reasonable way to cancel the cancellation.
Interrupt is a collaboration mechanism through which a thread can notify another thread to stop the current job and execute other jobs if appropriate or possible.
Public class Thread {public void interrupt (){...} // interrupt a thread public boolean isInterrupted (){...} // obtain the interrupt flag and determine whether to interrupt the public static boolean interrupted (){...} // clear the interrupt status and return its previous status value}
Each thread has a boolean interrupt state. When a thread is interrupted, the thread interruption status is set to true.
Calling interrupt does not mean to immediately stop the ongoing work of the target thread. Instead, it only transmits the request interruption message. In other words, it only modifies the flag field of the thread.
The correct understanding of the interrupt operation is: it does not actually interrupt a running thread, but only sends an interrupt request, and then the thread at the next appropriate time (cancel point) interrupt yourself. For example, sleep, wait, and join will strictly process such requests. An exception is thrown when they receive an interrupted request or find an interrupted state that has been set at the start of execution.
There are three conditions for canceling a thread task with Interruption
-Non-blocking interruption
-Stoppedblocking
-Uninterruptible Blocking
Interruption in non-blocking status
When a thread is interrupted in a non-blocking state, its interruption state will be set. If InterruptedException is not triggered, the interruption State will remain, then, the system checks the interruption status to determine whether the interruption has occurred.
You can poll the interrupt status of the current thread in the task code. to select an appropriate polling frequency, you need to weigh the efficiency and responsiveness.
Stoppedblocking Function interruption in the blocked Library
When wait/sleep/BlockingQueue. put and other methods that block the database are returned in advance when an interruption is detected, the operations they perform during the interruption include clearing the interruption status and throwing InterruptException.
Public void run () {while (! Thread. currentThread (). isInterrupted () {doSomething () ;}} private void doSomething () {try {Thread. sleep (100*1000); // blocking operation} catch (InterruptedException e ){//????? // Corresponding interrupt response} public void cancel () {interrupt ();}
While explicit detection is more responsive to interruptions.
How to respond to interruptions?
Response to interruption
1. An exception is passed, making calling a method an interrupt blocking method. To put it simply, add a declaration that throws an exception.
2. Restore the interrupted state so that the upper-Layer Code of the call stack can process it. The standard practice is to call interrupt again in catch to restore the interrupt State, so that the upper-Layer Code can process it.
In the above example, interrupt can be called again in the catch to restore the interrupt state. When the while LOOP does not meet the conditions again, it will exit. Consider the following example:
InterruptException can be blocked only when an interrupt policy is implemented in the code. The interrupt policy refers to what to do after receiving the interrupt request? For example, the following interrupt policy means that the thread exits immediately and no upper-layer code needs to know the interrupt information.
// InterruptException blocks interruption because he knows that the thread is about to end public void run () {try {while (! Thread. currentThread (). isInterrupted () {Thread. sleep (10*1000);} catch (InterruptedException e) {/* allow thread exit */} public void cancel () {interrupt ();}
Cancellation is not supported, but the method of interruption blocking can still be called.
You cannot cancel the operation, but can still call the operation that can interrupt the blocking method. When a catch is interrupted, the interrupt state should be saved locally, and the interrupted state should be restored before the return, rather than when the interruption state is captured. If the interrupted state is set too early, it may cause an infinite loop, because most of the interruptible blocking methods check the interrupt status at the entrance and immediately throw InterruptException when it is found that the status has been set
public Task getNextTask(BlockingQueue<Task> queue) { boolean interrupted = false; try { while (true) { try { return queue.take(); } catch (InterruptedException e) { interrupted = true; } } } finally { if (interrupted) Thread.currentThread().interrupt(); } }
Uninterruptible Blocking
Many blocking methods respond to interrupt requests by returning or throwing InterruptException in advance, so that developers can easily construct tasks that can cancel requests, however, not all blocking methods or blocking mechanisms can respond to interruptions. For example, socket I/O, wait for the built-in lock to be obtained, and the interrupt request can only set the thread interruption status, which has no other effect. We can use a method similar to interrupt to stop these threads, but this requires that we know the cause of thread blocking.
Synchronous Socket I/O Although the read and write methods in InputStream and OutputStream do not want to be interrupted, by disabling the underlying Socket, this can cause a SocketException to be thrown by a blocked thread that executes methods such as read and write. That is, close the underlying socket where the task needs to be canceled, and respond to the interruption in SocketException.
Public class CloseSocket extends Thread {private Socket socket; private InputStream in; public CloseSocket (Socket socket) throws IOException {this. socket = socket; this. in = socket. getInputStream () ;}@ Override public void interrupt () {try {// Closing this socket will also close the socket's InputStream and OutputStream. socket. close ();} catch (IOException e) {} finally {super. interrupt () ;}@override public void run () {try {byte [] buf = new byte [1024]; while (true) {int num = in. read (buf );//......}} catch (IOException e) {// The thread exits directly }}}
The interrupt method is rewritten to enable its skill to handle standard interruptions and also disable the underlying socket. Therefore, whether the thread is blocked in the read method or in an interruption-able blocking method, can be interrupted and the current work can be stopped.
We do not recommend that you use Java Thread Primitive Deprecation for Thread. stop and suspend.