“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()

  1. Interrupted() is a static method and isInterrupted() is a normal method
  2. 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.