Detailed explanation of Java thread interrupt

  • 2021-08-21 20:36:15
  • OfStack

Catalogue 1. Preface
2. Why Thread. stop is discarded 3. Meaning of thread interruption
3.1. Preliminary understanding
3.2. Interrupt wakes up blocked/dormant threads
3. 3, 1 flag bit exit thread 3. 4, thread interrupt exit 3. 5, flag bit + thread interrupt combination 4. Summary
5. Appendix

1. Preface

Everyone must have used Java thread development (Thread/Runnable), and the practice of starting one thread is usually:


new Thread(new Runnable(
 @Override
 public void run() {
  // todo sth...
 }
)).start();

However, when the thread exits, how do you do it? 1 There may be no more than the following two practices:

Set 1 flag bit: true/false to exit; Forced exit: thread. stop; (I'm sure no one will use this method now, because JDK also abandoned this method very early.)

It may also be suggested that I can exit the thread with interrupt! I can only say: Too Young Too Simple! An interrupt does not cause the thread to end and exit. An interrupt (interrupt) simply wakes up the blocked thread.

In this article, we will have a good talk: thread interruption, and how to use thread interruption correctly, and the correct thread exit.

2. Why is Thread. stop abandoned


This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it 
has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the 
objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to 
other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply 
modifies some variable to indicate that the target thread should stop running. The target thread should check this 
variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop 
running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method 
should be used to interrupt the wait.

The above is the source code annotation in the official JDK, and its meaning is as follows:

**The Thread. stop method is inherently unsafe. ** Using this method to stop a thread will cause all other threads locked because of the monitor lock "Monitor we talked about in synchronized, which is a built-in lock of Java" to be unlocked! (The essential consequence is that unchecked ThreadDeath exceptions propagate in the stack, thus unlocking the monitor lock). If any one object locked by the monitor is in a state of no one, it will be visible to other threads after being unlocked, with the potential result of any consequences. ** Instead of using the stop method, we should use a variable to tell the target thread to exit "This is the first method we mentioned at the beginning, set a flag bit". ** The target thread should periodically check this variable and correctly exit the run method based on this variable. If the target thread is in a blocking/hibernating state (for example, after using wait, sleep, yield methods, the thread gives up the right to use CPU, and then blocks/hibernates), the flag bit variable will not work at this time, then the interrupt method should be used to interrupt the blocking/hibernating state of the target thread and wake it up!

For the ThreadDeath object, the official added:

Threads can throw ThreadDeath exceptions almost anywhere. Because of this point, all synchronization methods and blocks will have to be considered in detail. When the thread cleans up the first ThreadDeath exception (in the catch or finally statement), it may throw the second. The cleanup will have to be repeated until it succeeds. The code to guarantee this 1 point will be complicated.

So, we don't want to go to try-catch ThreadDeath Exception!

Similarly, Thread. resume and Thread. suspend were discarded. These two methods are in danger of causing deadlock:

When using suspend, the lock is not released; If there is a certain situation to acquire the lock before resume, then a deadlock will be caused;

The correct way to replace these two methods is: Object. wait and Object. notify:

Because Object. wait releases the lock when it goes into a block.

3. What a thread break means

There are three interrupt-related methods in Thread:

Member method interrupt (): Set the thread interrupt flag to true; Member method isInterrupted (): Obtains the interrupt state of the thread, which defaults to false. After calling interrupt (), the method returns true; Static method Thread. interrupted (): Gets the thread's interrupt state and clears the interrupt state (set to false);

Note: If Thread. interrupted () is called twice in a row after a thread interrupts, the first is true & Clear the state, and the second result is false.

3.1. Preliminary understanding

Let's start with an example to get a preliminary understanding of thread. interrupt:


public class InterruptDemo implements Runnable {
 @Override
 public void run() {
  while (true) {
   System.out.println("Thread running...");
  }
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();

  Thread.sleep(50);
  System.out.println("interrupt thread");
  thread.interrupt();

  Thread.sleep(50);
  System.out.println("thread's status = " + thread.isInterrupted());
 }
}

Output:


start thread
Thread running...
Thread running...
......
interrupt thread
Thread running...
Thread running...
......
thread's status = true
Thread running...
......

We can see that even if we call the thread. interrupt method, the thread does not exit and continues to run. Therefore, this example proves one point: We can't try to "end" a running thread through "what we think" interrupts.

3.2. Interrupt wakes up blocked/dormant threads

Again, let's look at another example:


public class InterruptDemo implements Runnable {
 @Override
 public void run() {
  while (true) {
   System.out.println("Thread will sleep 10s ------------------------- running");
   long timestamp = System.currentTimeMillis();
   try {
    Thread.sleep(10000);
   } catch (InterruptedException e) {
    System.out.println("thread interrupted...");
   }

   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(3000);
  System.out.println("interrupt thread");
  thread.interrupt();
  System.out.println("main exit");
 }
}

Output:


start thread
Thread will sleep 10s ------------------------- running
interrupt thread
main exit
thread interrupted...
Thread run, total sleep = 3002(ms)
Thread will sleep 10s ------------------------- running
Thread run, total sleep = 10002(ms)
Thread will sleep 10s ------------------------- running

We can see that after the thread starts, it goes to sleep (10s), is interrupted to wake up after 3 seconds, goes to sleep for the second time (10s) after executing one while, and then goes on and on.

3.3, 1-like flag bit method exits thread


public class InterruptDemo implements Runnable {
 private static final AtomicBoolean running = new AtomicBoolean(true);

 @Override
 public void run() {
  while (running.get()) {
   long timestamp = System.currentTimeMillis();
   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
  System.out.println("Thread exit");
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(100);
  System.out.println("interrupt thread");
  thread.interrupt();
  running.set(false);
  System.out.println("main exit");
 }
}

Output:


start thread
.......
Thread run, total sleep = 0(ms)
interrupt thread
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
main exit
Thread exit

By using an AtomicBoolean variable as a flag bit, we enable our thread to exit normally. We can also judge whether the thread is interrupted and optionally exit.

3.4. Thread interrupts and exits


public class InterruptDemo implements Runnable {
 @Override
 public void run() {
  while (!Thread.currentThread().isInterrupted()) {
   long timestamp = System.currentTimeMillis();
   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
  System.out.println("Thread exit");
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(100);
  System.out.println("interrupt thread");
  thread.interrupt();
  System.out.println("main exit");
 }
}

Output:


start thread
.......
Thread run, total sleep = 0(ms)
interrupt thread
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
main exit
Thread exit

3.5. Flag bit + thread interrupt combination


This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it 
has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the 
objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to 
other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply 
modifies some variable to indicate that the target thread should stop running. The target thread should check this 
variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop 
running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method 
should be used to interrupt the wait.
0

Output:


This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it 
has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the 
objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to 
other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply 
modifies some variable to indicate that the target thread should stop running. The target thread should check this 
variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop 
running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method 
should be used to interrupt the wait.
1

4. Summary

In this article, we analyzed the interruption of threads and let everyone know the meaning of interruption: just tell the thread that you are "interrupted", and it is up to you to decide what you want to do. At the same time, we also briefly analyzed the reasons for several abandoned methods. I hope that after learning this article, we can design correctly and reasonably, and how to exit the thread safely.

5. Appendix

Object. wait: Blocks the current thread, releasing held locks; Object. notify: Wakes up the blocked thread on the current object and puts it in the ready state; Object. notifyAll: Wake up all threads; Thread. sleep: Specifies the current thread to sleep for a fixed time, giving up CPU, but not releasing the synchronization resource lock; Thread. yield: Give up the right to use CPU and let yourself and other threads compete for the opportunity to use CPU. Therefore, after using this method, there is no guarantee that the thread will get CPU again and resume running (after using this method, the thread with high priority has a higher probability of getting CPU, but the thread with low priority also has a probability of getting CPU and executing), and the synchronization resource lock will not be released in the same way;

The above is a detailed explanation of Java thread interrupt details, more information about Java thread interrupt please pay attention to other related articles on this site!


Related articles: