preface

In the introduction to Threads (2) of the previous article threads for Concurrent Programming in Java, we learned a little about how to create a thread and perform tasks, but we didn’t mention how to interrupt a thread. For example, we have a download thread that will not exit until the download is successful. If the user does not want to download at this point, how do we interrupt the download thread? Let’s learn how to interrupt a thread properly.

The outdated suspend(), resume(), and stop() methods are not covered here, but can be consulted by interested parties.

Interrupt mechanism for Java threads

When we need to interrupt a thread, it seems that all we need to do is call an interrupt method (after which the thread stops executing). But Java does not provide an actual way to interrupt a thread (leaving aside the outdated stop() method), only an interrupt flag bit to indicate that the thread has been interrupted by another thread while it is running. That is, the thread can only check the flag bit by itself to determine whether it has been interrupted. Three methods are provided to set or determine the interrupt flag bit in Java, as follows:

   // class method to set the flag bit in the current thread
   public void interrupt(a) {
        if (this! = Thread.currentThread()) checkAccess();synchronized (blockerLock) {
            Interruptible b = blocker;
            if(b ! =null) {
                interrupt0();           // Set the interrupt flag bit
                b.interrupt(this);
                return;
            }
        }
        interrupt0();// Set the interrupt flag bit
    }

    // Static method to determine whether the current thread is interrupted, clear the interrupt flag bit
    public static boolean interrupted(a) {
        return currentThread().isInterrupted(true);
    }

    // class method to determine whether the current thread is interrupted without clearing the interrupt flag
    public boolean isInterrupted(a) {
        return isInterrupted(false);
    }
Copy the code

In this method, interrupt() is used to set the corresponding Thread interrupt flag, and the Thread static method interrupted() and class method isInterrupted() are used to determine whether the corresponding Thread isInterrupted by another Thread.

The main differences between the interrupted () and isInterrupted () methods are as follows:

  • interruptedDetermines whether the current thread is interrupted (if interrupted, the interrupt status flag is cleared, that is, if the thread is interrupted, the first call to this method returns true, and the second call returns false.
  • isInterruptedDetermines whether the thread has been interrupted (without clearing the interrupted status flag).

Interrupt a thread with interrupt()

Now that you’ve seen how threads set and determine interrupt flags, let’s use the interrupt() method to interrupt a thread. Let’s look at this example.

class InterruptDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run(a) {
                for (int i = 0; i < 1000000; i++) {
                    System.out.println("i="+ i); }}}); thread.start();try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch(InterruptedException e) { e.printStackTrace(); }}}// Output result:
i=593210
i=593211
i=593212
i=593213
i=593214
i=593215
i=593216

Copy the code

Running the code above and looking at the output, we see that the thread is not being terminated because the interrupt() method only sets the thread interrupt flag and does not actually interrupt the thread. This means that we are the only ones who can determine whether a thread terminates. Normally, when we detect that a thread is interrupted (that is, the thread flag bit is true), an InterruptedException is thrown to interrupt the thread task. The specific code is as follows:

class InterruptDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    for (int i = 0; i < 1000000; i++) {
                        if (Thread.interrupted()) {
                            System.out.println("Thread interruption detected");
                            throw new InterruptedException();
                        }
                        System.out.println("i="+ i); }}catch (InterruptedException e) {
                    // Execute your own interrupt logic
                    System.out.println("The thread has been interrupted. Decide for yourself what to do about it."); e.printStackTrace(); }}}); thread.start();try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch(InterruptedException e) { e.printStackTrace(); }}}// Output result:
i=218626
i=218627
i=218628
i=218629
i=218630Detect the thread is interrupted thread was interrupted, you judge what to do with yourself Java. Lang. InterruptedException at InterruptDemo $1.run(InterruptDemo.java:18)
    at java.base/java.lang.Thread.run(Thread.java:835)
Copy the code

In the code above, we check whether a Thread has been interrupted by thread.interrupted () and throw InterruptedException when the Thread has been interrupted. We then execute our own interrupt logic by catching the exception with a try/catch. For example, thread.currentThread ().isinterrupted (). The differences between the two methods have been described above, but will not be covered here.

Another way to interrupt a thread

In addition to using interrupt() to interrupt a thread, as mentioned above, we can use a Boolean to control whether or not a thread is interrupted. Specific examples are as follows:

class InterruptDemo {

    public static void main(String[] args) {
        RunnableA runnableA = new RunnableA();
        Thread thread = new Thread(runnableA);
        thread.start();
        try {
            Thread.sleep(2000);
            runnableA.interruptThread();
        } catch(InterruptedException e) { e.printStackTrace(); }}static class RunnableA implements Runnable {
        boolean isInterrupt;

        @Override
        public void run(a) {
            for (int i = 0; i < 1000000; i++) {
                if(! isInterrupt) { System.out.println("i=" + i);
                } else {
                    System.out.println("The thread is finished running.");
                    break; }}}void interruptThread(a) {
            isInterrupt = true; }}}// Output result:
i=240399
i=240400
i=240401
i=240402
i=240403
i=240404
i=240405The thread is finished runningCopy the code

In the code above, we determine if we are breaking the loop by checking the value of isInterrupt. The end of the run () method signals that the thread has finished executing.

The last

Standing on the shoulders of giants, can see further ~

  • The Art of Concurrent Programming in Java