“This is the 21st day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021”
preface
When referring to how to terminate a thread, some readers usually method must be stop immediately think of (), but the stop () method is not recommended to use (a lot of specification is forbidden to use), the reason is forced to terminate a thread, can lead to the end of the program is not normal, and there will be a resource is not properly released, application result is not correct, and so on. Whether to terminate a thread should transfer control to the currently terminating thread itself, in this case using the ****interrupt() method, which changes the value of a shared variable and continues running when the running thread determines that the current value is false. This value changes to true if the current thread’s interrupt() method is called somewhere, and the current thread can terminate the thread correctly based on this change.
API
Java.lang.Thread mainly provides the following methods related to Thread interrupts, whose specific method names and main functions are listed in the following table.
The method name | Methods effect |
---|---|
public void interrupt() | Interrupt this thread |
public static boolean interrupted() | Tests whether the current thread is interrupted, and restores (clears) the interrupt flag |
public boolean isInterrupted() | Tests whether the current thread is interrupted. This method only retrieves the interrupt flag and does not recover (clear) the interrupt flag |
private native boolean isInterrupted(boolean ClearInterrupted); | Interrupted() and isInterrupted() are eventually called. This method is native and implemented in the JVM, and is also the method that gets the thread interrupt flag actually called. ClearInterrupted means whether to restore (clear) the interrupt flag |
The source code
Public void interrupt() {if (this! = Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b ! = null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); } public static Boolean interrupted() {return currentThread().isinterrupted (true); } /** * Public Boolean isInterrupted() {return isInterrupted(false); } /** * whether the thread isInterrupted native method, ClearInterrupted flag parameter */ private native Boolean isInterrupted(Boolean ClearInterrupted); /** * Interrupt the current thread native method */ private native void Interrupt0 ();Copy the code
Interrupted() and isInterrupted()
After looking at the API for interruption () and the source code for Thread, you can see the main difference between interrupted() and isInterrupted()
- Interrupted() is a static method and isInterrupted() is a normal method
- Interrupted() returns the interrupt flag and clears (restores) the interrupt flag, isInterrupted() returns only the interrupt flag
Method of use
We first verify the interrupt exception response, through the use of the following two methods to introduce the example, notice the Runner in the run method part of the difference
Methods a
package com.liziba.p7; import java.util.concurrent.TimeUnit; /** * <p> * * </p> * * @Author: Liziba * @Date: 2021/6/24 21:05 */ public class ThreadInterruptedDemo { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runner(), "Thread-01"); t1.start(); Timeunit.seconds.sleep (1); timeunit.seconds.sleep (1); // Initiate interrupt t1.interrupt(); } static class Runner implements Runnable { @Override public void run() { while (! Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName() + " is running ."); }}}}Copy the code
The output
You can see that the thread terminates after several executions
Method 2
package com.liziba.p7; import java.util.concurrent.TimeUnit; /** * <p> * * </p> * * @Author: Liziba * @Date: 2021/6/24 21:18 */ public class ThreadInterruptedDemo { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runner(), "Thread-01"); t1.start(); Timeunit.seconds.sleep (1); timeunit.seconds.sleep (1); // Initiate interrupt t1.interrupt(); } static class Runner implements Runnable { @Override public void run() { while (! Thread.currentThread().isInterrupted()) { System.out.println(Thread.currentThread().getName() + " is running ."); Timeunit.seconds.sleep (2); timeunit.seconds.sleep (2); } catch (InterruptedException e) {// Do nothing about the interrupt, try the exception, print e.printStackTrace(); } } } } }Copy the code
The output
You can see that the t1 thread interrupts from the main thread. After catching the exception, the thread continues to run without doing anything
Sum up the above two ways
Methods 1 and 2 run the logic in the run method by checking whether thread.currentThread ().isinterrupted () returns false if the Thread has not been interrupted. If t1.interrupt() isInterrupted in the main Thread and t1 isInterrupted, thread.currentthread ().isinterrupted () changes to false; In method 1, the execution is terminated after the change is obtained. In method 2, the thread blocks in response to the interrupt because of sleep(), but I only catch the exception and do nothing with the interrupt. The point here is that the interrupt flag is restored when the thread throws an exception in response to the interrupt, so t1.interrupt() changes to the interrupt flag are restored. The program is still running.
\
Next we verify that interrupted() clears the interrupt flag
package com.liziba.p7; import java.util.concurrent.TimeUnit; /** * <p> * isInterrupted() * </p> * * @Author: Liziba * @Date: 2021/6/24 21:20 */ public class ThreadInterruptDemo2 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runner(), "Thread-1"); thread.start(); TimeUnit.SECONDS.sleep(2); thread.interrupt(); } static class Runner implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() +" interrupted flag is " + Thread.currentThread().isInterrupted()); while (! Thread.currentThread().isInterrupted()) { try { System.out.println(Thread.currentThread().getName() + " is running ."); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {thread.currentThread ().interrupt(); // Call isInterrupted() to get the current interrupt flag system.out.println (thread.currentThread ().getName() +" interrupted Flag is "+ Thread.currentThread().isInterrupted()); } } } } }Copy the code
The output
This proves that interrupted() does not know the interrupt flag, and the thread ends after receiving the interrupt from Thread.interrupt ().
Change thread.currentThread () in catch above to thread.interrupted () and run again
package com.liziba.p7; import java.util.concurrent.TimeUnit; /** * <p> * * </p> * * @Author: Liziba * @Date: 2021/6/24 21:23 */ public class ThreadInterruptDemo2 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runner(), "Thread-1"); thread.start(); TimeUnit.SECONDS.sleep(2); thread.interrupt(); Static class Runner implements Runnable {@override public void run() { System.out.println(Thread.currentThread().getName() +" interrupted flag is " + Thread.currentThread().isInterrupted()); while (! Thread.currentThread().isInterrupted()) { try { System.out.println(Thread.currentThread().getName() + " is running ."); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {thread.currentThread ().interrupt(); System.out.println(thread.currentThread ().getName() +" interrupted flag is "+ thread.interrupted ()); } } } } }Copy the code
The output
The thread responds to thread.interrupt(), but because thread.interrupt() is called in catch, the interrupt flag is cleared. Thread.currentthread ().isinterrupted () Returns true and the Thread continues running
Now that you understand the main differences between the two methods and their use, let’s look at the next use case in the source code. By watching our AbstractQueuedSynchronizer (AQS) in await () method, to see its use in the source code.
Public final void await() throws InterruptedException { If (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); int interruptMode = 0; while (! isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) ! = 0) break; } if (acquireQueued(node, savedState) && interruptMode ! = THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter ! = null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode ! = 0) reportInterruptAfterWait(interruptMode); }Copy the code
AbstractQueuedSynchronizer (AQS) source is used in static Thread. Interrupted (), judge whether the current Thread is interrupted, and restore the interrupt flag, if the Thread has been interrupted by throwing an exception InterruptedException interrupt. The purpose of clearing the flag bit is to allow the current thread to perform subsequent operations when it re-enters after responding to the interrupt.