This note is combed by Wolai, welcome to visit and point out any problemswww.wolai.com/mucong/8EaQ…

3.1 Principles


  • In Java, the best way to stop a thread is to use interrupts, butThis simply tells the terminated thread “You should stop running.”, the terminated threadHave the right to decide(to decide if and when to stop), which depends on both the requesting party and the stopped party complying with oneAgreed coding specifications.

  • Starting tasks and threads is easy. Most of the time, we let them run until the end, or let them stop themselves. However, sometimes we want to terminate a task or thread early, perhaps because the user canceled an action, or the service needs to be shut down quickly, or because the run timed out or went wrong.

  • It is not easy to stop tasks and threads safely, quickly, and reliably. Java does not provide any mechanism for safely terminating threads. But it provides Interruption, which is a cooperative mechanism that can cause one thread to terminate the current work of another thread.

  • This collaborative approach is necessary, and we rarely want a task, thread, or service to stop immediately, because such an immediate stop would leave the shared data structure in an inconsistent state. Instead, tasks and services can be written in a collaborative fashion: when they need to stop, they first clean up the work currently being performed and then finish. This provides greater flexibility because the code of the task itself knows better how to perform the cleanup than the code that makes the cancellation request **. **

  • End-of-life issues complicate the design and implementation of tasks, services, and programs, an important element of programming that is often overlooked. One of the main differences between well-behaved software and poorly functioning software is that well-behaved software handles failures, shutdowns, and cancellations perfectly.


3.2 Best Practices


Conclusion early

  • Preferred: delivery interrupt

  • Unwilling or unable to deliver: Resuming the interrupt

  • Should not beshieldinginterrupt

When does a thread stop

  • The run() method completes execution

  • An exception occurred and no catch was made

  • The correct way to stop: use the interrupt() method

3.2.1 When do threads normally stop


  • Stops the thread if there are no sleep or wait methods in the run method

  • Stop a thread with interrupt()

  • Used when using interrupt()! Thread.currentthread ().isinterrupted () Checks whether the interrupt command is received

  • Using code to demonstrate

public class RightWayStopThreadWithoutSleep implements Runnable{
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new RightWayStopThreadWithoutSleep());
        thread.start();
        Use the interrupt method to tell a thread to stop
        thread.sleep(1000);
        thread.interrupt();

    }
    @Override
    public void run(a) {
        int number = 0 ;
        //Thread.currentThread().isInterrupted() 
        // This method can determine whether the method received an interrupt instruction
        while (number <= Integer.MAX_VALUE/2 && !Thread.currentThread().isInterrupted()){
            if (number%10000= =0){
                System.out.println(number);
            }
            number++;
        }
        System.out.println("Mission over."); }}Copy the code

Stop the thread in case of blocking


  • Stops the child thread when it blocks itself

  • Stop a thread with interrupt()

  • Used when using interrupt()! Thread.currentthread ().isinterrupted () Checks whether the interrupt command is received

  • With sleep blocking, the interrupt notification causes the thread to throw an exception in response to the interrupt notification and then stop the thread

  • Using code to demonstrate

public class RightWayStopThreadWithSleep {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = ()->{
            int number = 0;
            try {
            while ( number <= 300 && !Thread.currentThread().isInterrupted()){
                if ( number%100= =0){
                    System.out.println(number);
                }
                number++;
            }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Mission accomplished.");
        };
        Thread thread = new Thread(runnable);
        thread.start();
        thread.sleep(500); thread.interrupt(); }}Copy the code

3.2.3 If the thread blocks after each iteration


  • If sleep or wait methods were called during each iteration, we would not need to check for interrupts on each iteration

  • Stop a thread with interrupt()

  • You don’t need to use interrupt()! Thread.currentthread ().isinterrupted () Checks whether the interrupt command is received

  • Using code to demonstrate

public class RightWayStopThreadWithSleepEveryLoop {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = ()->{
            int number = 0;
            try {
                while ( number <= 10000) {if ( number%100= =0){
                        System.out.println(number);
                    }
                    number++;
                    // Generates a block
                    Thread.sleep(10); }}catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Mission accomplished.");
        };

        Thread thread = new Thread(runnable);
        thread.start();
        thread.sleep(5000); thread.interrupt(); }}Copy the code

3.2.4 Try /catch problems in while


  • If we put a THR -catch in the while, the interrupt will fail

  • Cause: : When the sleep function is designed to respond to the interrupt, the interrupt flag will be cleared, so when the thread stops, the exception of sleep can not be handled simply, should be thrown to a higher level method for processing. / / todo to be perfect

  • Using code to demonstrate

/** * Created by mucong on 2021/1/16 19:36 ** * Created by Mucong on 2021/1/16 19:36 ** * Created by Mucong on 2021/1/16 19:36 **
public class CantInterrupt {

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = ()->{
          int number = 0 ;

          while ( number<= 10000) {if ( number%100= =0 ){
                  System.out.println(number);
              }
              number++;
              try {
                  Thread.sleep(10);
              } catch(InterruptedException e) { e.printStackTrace(); }}}; Thread thread =new Thread(runnable);
        thread.start();
        thread.sleep(5000); thread.interrupt(); }}Copy the code

3.2.5 Prioritization of two best practices in actual development


  • Because of the special mechanism of Sleep, we need to design a proper way to stop the thread without clearing the interrupt flag bit.

  • Preferentially throw exceptions on methods. Mark your method with InterruptedException. Catch the exception without using a try block so that the exception can be passed to the top level so that the Run method can catch it, for example:

void subTask(a) throws InterruptedException
  sleep(delay);
}
Copy the code
  • Advantages: Because the run method cannot throw a Checked Exception (only a try catch), the top-level method must handle the Exception, avoiding the possibility of missing or being swallowed, which increases the robustness of the code.

  • Using code to demonstrate

/** * Created by Mucong on 2021/1/17 17:43 ** Best practice 1: Catch InterruptException Throw an exception in the method signature, and run() forces try/catch * */
public class RightWayStopThreadInProd implements Runnable{
    @Override
    public void run(a) {
        while ( true && !Thread.currentThread().isInterrupted()){

            System.out.println("go");
            try {
                throwInMethod();
            } catch (InterruptedException e) {
                System.out.println("Save log"); e.printStackTrace(); }}}// This method throws an interrupt exception using throws throws
    // If you use try/catch, the block will be swallowed
    private void throwInMethod(a) throws InterruptedException {

            Thread.sleep(2000);

    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new RightWayStopThreadInProd());
        thread.start();
        Thread.sleep(1000); thread.interrupt(); }}Copy the code

3.2.6 Recovery interruption of two best practices in actual development


  • The second solution is to also avoid sleep’s special mechanism of clearing interrupt markers,

  • The first way is to avoid the special mechanism of sleep, of course, after starting the special mechanism, the interrupt signal can be marked ==== to restore the interrupt

  • Use: If you do not want to or cannot pass InterruptedException (for example, throw InterruptedException when using the RUN method), Instead, call thread.currentThread ().interrupt() in the catch clause to restore the interrupt state so that subsequent executions can still detect that the interrupt occurred.

  • Here, the thread is interrupted during a sleep, caught by a catch, and the interrupted state is reset so that it can detect the interrupted state on the next loop and exit normally.

 /** * Created by Mucong on 2021/1/17 18:18 ** Call thread.currentThread ().interrupt() in the catch statement to restore the * break state so that subsequent executions can still detect the interrupt that just occurred */
public class RightWayStopThreadInProd2 implements Runnable{
    @Override
    public void run(a) {
        while ( true) {if (Thread.currentThread().isInterrupted()){
                System.out.println("Save log");
                break;
            }
            System.out.println("go"); reInterrupt(); }}// Use try/catch and resume the interrupt in the catch
    //Thread.currentThread().interrupt();
    private void reInterrupt(a)  {

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // Use the interrupt method for interrupt recoveryThread.currentThread().interrupt(); e.printStackTrace(); }}public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new RightWayStopThreadInProd2());
        thread.start();
        Thread.sleep(1000); thread.interrupt(); }}Copy the code

3.2.7 Method of response to interrupt

--- - All of the following methods respond to interrupt signals from the interrupt! [](https://secure-static.wolai.com/static/rqMn9mPSv1r6f399FoxYSw/image.png) ! [](https://secure-static.wolai.com/static/jxC6bvSM5jDdsxtaiKDNn7/image.png)Copy the code

3.3 Incorrect Stop Mode


  • Deprecated stop, suspend, and resume methods

  • Set the Boolean flag bit with volatile

Volatile incorrect parsing: This is incorrect, or incomplete, and may work in some cases, but in others it is seriously problematic.

This approach was clearly identified in Java Concurrent Programming In Action, so let’s take a look at what the flaws are:

  • Error cause: If we encounter a thread that blocks for a long time (a very common situation, such as in the producer-consumer pattern), we can’t wake it up in time, or we can never wake it up. Interrupt is designed to allow for a long block such as wait as a special case. We should stop threads with interrupt thinking.

  • Code demo part1: code that seems to work

/** * Created by mucong on 2021/1/23 15:41 * 

* description: demonstrating the limitations of volatile: part1-- plausible */

public class WrongWayVolatile implements Runnable { // Set a flag bit private volatile boolean canceled = false; @Override public void run(a) { int num = 0; try { while (num <= 10000 && !canceled) { if (num % 100= =0) { System.out.println(num + "It's a multiple of 100."); } num++; Thread.sleep(1); }}catch(InterruptedException e) { e.printStackTrace(); }}public static void main(String[] args) throws InterruptedException { WrongWayVolatile r = new WrongWayVolatile(); Thread thread = new Thread(r); thread.start(); Thread.sleep(5000); r.canceled=true; }}Copy the code
  • Code demo part2: inapplicable situations
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/** * Created by Mucong on 2021/1/23 16:48 * 

* Description: Demonstrating the limitations of using volatile part2: * Volatile cannot interrupt a thread when it blocks * eg: Producers are producing too fast and consumers are consuming too slowly, so there will be a blocking queue when the queue is full, * producers will block, waiting for consumers to consume. * /

public class WrongWayVolatileCantStop { public static void main(String[] args) throws InterruptedException { // When it is full, it cannot be put in, and when it is empty, it cannot be taken out ArrayBlockingQueue storage = new ArrayBlockingQueue(10); // The producer thread Producer p1 = new Producer(storage); Runnable target; Thread producerThread = new Thread(p1); producerThread.start(); Thread.sleep(1000); // Consumer thread Consumer consumer = new Consumer(storage); while (consumer.needMoreNums()){ System.out.println(consumer.storage.take()+"Consumed."); Thread.sleep(100); } System.out.println("Consumers don't need more data."); // Once consumers don't need more data, producers should stop, but p1.cancel = true; }}class Producer implements Runnable { public volatile boolean cancel = false; BlockingQueue storage; public Producer(BlockingQueue storage) { this.storage = storage; } @Override public void run(a) { int num = 0; try { while (num <= 10000 && !cancel) { if (num % 100= =0) { storage.put(num); System.out.println(num + "It's a multiple of 100. It's in storage."); } num++; }}catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("The producer stopped running"); }}}class Consumer { BlockingQueue storage; public Consumer(BlockingQueue storage) { this.storage = storage; } // Determine whether to consume public boolean needMoreNums(a) { if (Math.random() > 0.95) { return false; } return true; }}Copy the code
  • To stop by means of interruption
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/** * Created by mucong on 2021/1/23 17:37 *
public class WrongWayVolatileFixed {
    public static void main(String[] args) throws InterruptedException {

        WrongWayVolatileFixed body = new WrongWayVolatileFixed();
        // When it is full, it cannot be put in, and when it is empty, it cannot be taken out
        ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
        // The producer thread
        Producer p1 = body.new Producer(storage);
        Runnable target;
        Thread producerThread = new Thread(p1);
        producerThread.start();
        Thread.sleep(1000);
        // Consumer thread
        Consumer consumer = body.new Consumer(storage);
        while (consumer.needMoreNums()){
            System.out.println(consumer.storage.take()+"Consumed.");
            Thread.sleep(100);
        }
        System.out.println("Consumers don't need more data.");

        // Once consumers don't need more data, producers should stop, but
        producerThread.interrupt();
    }
        / / producer
        class Producer implements Runnable {

            BlockingQueue storage;

            public Producer(BlockingQueue storage) {
                this.storage = storage;
            }

            @Override
            public void run(a) {
                int num = 0;
                try {
                    while (num <= 10000 && !Thread.currentThread().isInterrupted()) {
                        if (num % 100= =0) {
                            storage.put(num);
                            System.out.println(num + "It's a multiple of 100. It's in storage."); } num++; }}catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("The producer stopped running"); }}}/ / consumer
        class Consumer {
            BlockingQueue storage;

            public Consumer(BlockingQueue storage) {
                this.storage = storage;
            }
            // Determine whether to consume
            public boolean needMoreNums(a) {
                if (Math.random() > 0.95) {
                    return false;
                }
                return true; }}}Copy the code

3.4 Stop thread important function analysis


  • Public static Boolean Interrupted () : Checks whether to interrupt and clears the status ==== Target object: main thread

    • The source code is as follows:
    public static boolean interrupted(a) {
        return currentThread().isInterrupted(true);
    }

Copy the code
  • Public Boolean isInterrupted() : Checks whether to interrupt and does not clear the current status ==== target object: the calling thread

    • The source code is as follows
public boolean isInterrupted(a) {
        return isInterrupted(false);
    }
Copy the code

3.5 Common Interview Questions


3.5.1 How do I Stop a Thread

  • In the following order:
  1. How it works: It’s good to use interrupts to make requests

  2. Stopping a thread requires the cooperation of the requester, the requested, and the submethod called

  3. Finally, the wrong method: stop/suspend is deprecated, and volatile Boolean does not handle long blocking

  • Details are as follows:
  1. How it works: Using interrupts to ask a thread to stop, rather than forcing it to, is safe.

  2. To stop a thread, the requester, the stopped party, and the submethod called need to cooperate:

- As the stopped party: ** Check the interrupt signal ** in each loop ** or when appropriate, and process the interrupt signal ** where an InterrupedException can be thrown **; - Requester: send interrupt signal; - The submethod caller (the author of the method called by the thread) should note: ** First throw an InterrupedException at the method level, or set the interrupt status again when an interrupt signal is detected **;Copy the code
  1. Finally, the wrong method: Stop /suspend is deprecated, and volatile Boolean does not handle prolonged blocking

3.5.2. How to handle non-interruptible blocking

If a thread is blocked by calling wait(), sleep(), or join(), you can interrupt the thread and wake it up by throwing InterruptedException. Unfortunately, there is no universal solution for blocking that does not respond to InterruptedException. - * * * * we can use a specific method of other can interrupt response, such as: - already. LockInterruptibly (), such as closing the socket threads returns immediately and other methods to achieve a goal. - There are many answers, because there are many reasons for a thread to block, so the method of arousal varies according to the situation. - ** Summary means that if response interrupts are not supported, specific methods should be used to evoke them. There is no panacea. **Copy the code