interrupted() and isInterrupted() are still half understood?

Keywords: Java Database Back-end Programmer Distribution

 

preface

When it comes to how to terminate a thread, the method that some readers usually think of immediately must be stop(), but the stop() method is not recommended (it is prohibited in many specifications). The reason is that forcibly terminating a thread will lead to abnormal termination of the program, incorrect release of resources, incorrect program results and so on. If you want to terminate a thread, you should transfer this control to the currently terminated thread itself. At this time, you use the * * * * interrupt() method to terminate. This method is equivalent to modifying the value of a shared variable. When the running thread judges that the current value is false, it will continue to run. If there is a place to call the interrupt() method of the current thread, Then this value will change to true. At this time, the current thread can correctly terminate the operation of the thread according to the modification of this value.

API

The following methods related to thread interrupt are mainly provided in java.lang.Thread. The specific method name and main functions are shown in the table below.

Method nameMethod function
public void interrupt()Interrupt this thread
public static boolean interrupted()Tests whether the current thread is interrupted. This method restores (clears) the interrupt flag
public boolean isInterrupted()Test whether the current thread is interrupted. This method will only get the interrupt flag and will not recover (clear) the interrupt flag
private native boolean isInterrupted(boolean ClearInterrupted);interrupted() and isInterrupted() are finally called. This method is a native method, which is implemented in the jvm. It is also a method to get the thread interrupt flag. The parameter ClearInterrupted means whether to recover (clear) the interrupt flag

Source code

/**
 * Interrupt this thread
 */
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();
}

/**
 *	Test whether the current thread is interrupted and return the interrupt flag
 */
public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

/**
 *	Test whether the current thread is interrupted and return the interrupt flag
 */
public boolean isInterrupted() {
    return isInterrupted(false);
}

/**
 * Whether the thread is interrupted. The native method, ClearInterrupted, is whether to clear the interrupt flag parameter
 */
private native boolean isInterrupted(boolean ClearInterrupted);

/**
 *	Interrupt the native method of the current thread
 */
private native void interrupt0();
Copy code

What is the difference between interrupted() and isInterrupted()

After reading the above API description and the source code in 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 (resumes) the interrupt flag, isInterrupted() returns only the interrupt flag

usage method

We first verify the interrupt exception response, and introduce it through the use examples of the following two methods. Note some differences between the run methods in Runner

Method 1

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();
        // The main thread sleeps for 1 second to ensure the full execution of t1
        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 code

Output results

You can see that the thread terminates after executing several times

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();
        // The main thread sleeps for 2 seconds to ensure the full execution of t1
        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 .");
                try {
                    // Sleep for 2 seconds to ensure that the interrupt initiated by the main thread can be captured
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    // Do not deal with interrupts, try to stop exceptions and print
                    e.printStackTrace();
                }
            }
        }
    }

}
Copy code

Output results

You can see that the t1 thread interrupt initiated in the main thread continues to run without any processing after the exception is caught

Summarize the above two methods

Methods 1 and 2 run the logic in the run method by judging the value of Thread.currentThread().isInterrupted(). Thread.currentThread().isInterrupted() returns false when the thread is not interrupted. When t1.interrupt() is executed in the main thread, thread t1 is interrupted, and the value of Thread.currentThread().isInterrupted() becomes false; In method 1, after obtaining this change, the operation is ended directly; In method 2, because sleep() causes the thread to block and respond to the interrupt, but at this time, I only catch the exception and do not deal with the interrupt. Here's a knowledge point: when the thread throws an exception in response to the interrupt, the interrupt flag will be restored (cleared). Therefore, the modification of the interrupt flag by t1.interrupt() has been restored, and the program still runs continuously.

\

Next, let's 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) {
                    // In response to an interrupt, the interrupt position will be reset after an exception is thrown
                    Thread.currentThread().interrupt();
                    // Here, call isInterrupted() to get the current interrupt flag
                    System.out.println(Thread.currentThread().getName()
                            +" interrupted flag is " + Thread.currentThread().isInterrupted());
                }
            }
        }
    }

}
Copy code

Output results

It is proved here that interrupted() does not know the interrupt flag. After the thread obtains the interrupt initiated by thread.interrupt(), the execution ends.

Modify Thread.currentThread().isInterrupted() in the above catch 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();
    }

    // The difference is in catch
    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) {
                    // In response to an interrupt, the interrupt position will be reset after an exception is thrown
                    Thread.currentThread().interrupt();
                    // Notice the difference here
                    System.out.println(Thread.currentThread().getName()
                            +" interrupted flag is " + Thread.interrupted());
                }
            }
        }
    }

}
Copy code

Output results

The thread also responds to the interruption of thread.interrupt(), but because the Thread.interrupted() is called in catch, the interrupt flag is cleared, so! Thread.currentThread().isInterrupted() judges that it is still equal to true, and the thread continues to run

See here, you should have understood the main differences between the two methods and their use. Finally, let's look at the use case in the next source code. Let's look at the await() method in AbstractQueuedSynchronizer (AQS) to see its use in the source code.

public final void await() throws InterruptedException {
    // Judge whether the current thread is interrupted. If it is interrupted, restore the interrupt flag
    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 code

The static Thread.interrupted() is used in the AbstractQueuedSynchronizer (AQS) source code to judge whether the current thread is interrupted and recover the interrupt flag. If the thread has been interrupted, an interrupt exception of InterruptedException will be thrown. The purpose of clearing the flag bit is to enable subsequent operations when the current thread enters again after responding to an interrupt.

Posted by Patrick on Sun, 21 Nov 2021 13:41:24 -0800