In the previous article I -code. Online – Concurrent Programming – Thread Basics we covered thread creation and termination, understanding the details from a source point of view. Now if someone asks you “How do I gracefully stop a thread?” How do you answer Ny? Can you answer me perfectly?

  • Stop for thread, normally we wouldn’t have to manually to stop, but the waiting thread to run to the end stop nature, but in our actual development, there will be many cases we are need to manually in advance to stop the thread, such as abnormal in the program errors, such as the user to shut down the program, and so on and so forth. Failing to stop threads properly in these scenarios can lead to all kinds of problems, so it is important to have a proper stop procedure.

What happens when threads are forcibly stopped?


  • During the development of our usual we won’t pay attention to whether the thread is robust to most of the time, the ability to stop, elegant, in many cases are cut in forced to stop the running threads, it might cause some security problems, in order to avoid this loss, we should give proper time to handle threads and finishing touches by the current thread, Without affecting our business.

  • For Java, the most correct way to stop a thread is to use interrupts. But the interrupt merely notifies the stopped thread. For the stopped thread, it has full autonomy, it can choose to stop immediately, after a period of time, or choose not to stop at all. Many students may wonder, what is the point of this existence? In fact, for Java, programs are expected to be able to notify each other and cooperate with management threads

  • We have a thread in the IO operations, for example, when a program is writing files to the do, then receive signals to terminate the thread, so it will not stop immediately, it will be judged according to their own business. What should I do, is to stop after the file is written to success or not stop depends on be notified of thread processing, etc. Terminating the thread immediately here could result in data incompleteness, which is undesirable for our business.

Interrupt stops a thread

  • aboutinterruptWe are not going to elaborate on the use ofI-code. online – Concurrent Programming – Thread BasicsThe core of this introduction is through the call threadisInterrupt()Method to determine the interrupt signal, when the thread detectstrue“, it means that the termination signal is received, at this time, we need to do the corresponding processing


  • Let’s write a simple example
 Thread thread = new Thread(() -> {
            while (true) {
                // Check whether the current thread is interrupted.
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread 1 received an interrupt message, the interrupt thread... Interrupt flag:" + Thread.currentThread().isInterrupted());
                	// Exit the loop and terminate the thread
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "Thread executing..."); }},"interrupt-1");
        // Start thread 1
        thread.start();

        // Create interrupt-2 threads
        new Thread(() -> {
            int i = 0;
            while (i <20){
                System.out.println(Thread.currentThread().getName()+"Thread executing...");
                if (i == 8){
                    System.out.println("Set thread interrupt...." );
                    Thread 1 sets interrupt notification
                    thread.interrupt();

                }
                i ++;
                try {
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch(InterruptedException e) { e.printStackTrace(); }}},"interrupt-2").start();
Copy the code

The above code is relatively simple, we created two threads, the first thread made of our interrupt signal detection, when receives the interrupt request end circulation, natural termination of the thread, the thread 2, we simulated when the execution to I = = 8 let the thread is terminated, this case, we can see the program for the natural end.

Here’s a thought: when in a sleep, can a thread feel an interrupt signal?

  • For this particular case, we can verify this by modifying the above code slightly, by adding thread 1’s codesleepAt the same time, the sleep time is lengthened so that thread 1 is still sleeping when thread 2 notifies, and then observe whether the interruption signal can be felt
        // Create interrupt-1 threads

        Thread thread = new Thread(() -> {
            while (true) {
                // Check whether the current thread is interrupted.
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread 1 received an interrupt message, the interrupt thread... Interrupt flag:" + Thread.currentThread().isInterrupted());
                    Thread.interrupted(); // // resets the thread from true to false
                    System.out.println("After thread.interrupted () is reset, interrupt marks:" + Thread.currentThread().isInterrupted());

                    // Again determine whether to interrupt, if so, exit the thread
                    if (Thread.currentThread().isInterrupted()) {
                        break;
                    }
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "Thread executing...");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch(InterruptedException e) { e.printStackTrace(); }}},"interrupt-1");
Copy the code

If the methods used to block a thread, such as sleep or wait, cause it to sleep and interrupt, the thread senses the interrupt signal, throws an InterruptedException and clears the interrupt signal. Set the interrupt flag bit to false. This way, you don’t have to worry about threads not feeling interrupts during a long sleep, because threads can still respond to interrupt notifications and throw exceptions even while they are sleeping.

The most elegant way to stop a thread is to interrupt it. Read about InterruptedException in the previous article and set it again to allow the program to continue with the termination. However, interrupt thread termination has not been used very much in the real world, and many people may prefer to use it the other way, through token bits.

The stopping method for marking bits with volatile

  • aboutvolatileAs the core of the tag bit is its visibility feature, we can look at it through a simple code:

/ * * *@ulr: i-code.online
 * @author: zhoucx
 * @time: 2020/9/25 14:45 * /
public class MarkThreadTest {

    // define the tag to use volatile modifier
    private static volatile  boolean mark = false;

    @Test
    public void markTest(a){
        new Thread(() -> {
            // Check the flag bit to determine whether to proceed
            while(! mark){try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread execution content...");
            }
        }).start();

        System.out.println("This is the main thread going...");
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // After 10 seconds will be marked to set true visible to the thread. With volatile
        mark = true;
        System.out.println("Change the flag bit to:"+mark); }}Copy the code

The code above is a set of flags that the thread can see and terminate the program. The point here is that volatile is true and is fine in all of these scenarios, but volatile is problematic in some special scenarios. This is also something to watch out for!

Volatile modifies scenarios where the tag bit does not apply

  • Here we use a production/consumption pattern to implement oneDemo

/ * * *@url: i-code.online
 * @author: zhoucx
 * @time: 2020/10/12 10:46
 */
public class Producter implements Runnable {

    // Whether the tag needs to produce a number
    public static volatile boolean mark = true;

    BlockingQueue<Integer> numQueue;

    public Producter(BlockingQueue numQueue){
        this.numQueue = numQueue;
    }

    @Override
    public void run(a) {
        int num = 0;
        try {
            while (num < 100000 && mark){
                // Add the number to the queue
                if (num % 50= =0 ){
                    System.out.println(num + It's a multiple of 50. Join the queue.); numQueue.put(num); } num++; }}catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("End of producer run...."); }}}Copy the code

First, we declare a Producer, Producer, that stops the thread with the Boolean mark of the volatile flag starting with true. In the run() method, the judgment statement of the while is whether num is less than 100000 and mark is marked. If num is a multiple of 50, put it into numQueue, which is the memory used by producers and consumers to communicate with each other. When num is greater than 100000 or is told to stop, It breaks out of the while loop and executes a finally block, telling everyone that the producer is finished.


/ * * *@url: i-code.online
 * @author: zhoucx
 * @time: 2020/10/12 11:03 * /
public class Consumer implements Runnable{

    BlockingQueue numQueue;

    public Consumer(BlockingQueue numQueue){
        this.numQueue = numQueue;
    }

    @Override
    public void run(a) {

        try {
            while (Math.random() < 0.97) {// Make a purchase
                System.out.println(numQueue.take()+"Consumed...");;
                TimeUnit.MILLISECONDS.sleep(100); }}catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("End of consumer enforcement...");
            Producter.mark = false;
            System.out.println("Producter.mark = "+Producter.mark); }}}Copy the code

As for the Consumer, it shares the same warehouse as the producer, numQueue. In the run() method, we determine whether to continue to consume by judging the random number size. The producer just produced some multiples of 50 for the Consumer to use. The judgment condition for consumers to continue to use numbers is to generate a random number and compare it with 0.97. If the number is greater than 0.97, they will not continue to use numbers.


/ * * *@url: i-code.online
 * @author: zhoucx
 * @time: 2020/10/12 11:08 * /
public class Mian {


    public static void main(String[] args) {
        BlockingQueue queue = new LinkedBlockingQueue(10);

        Producter producter = new Producter(queue);
        Consumer consumer = new Consumer(queue);

        Thread thread = new Thread(producter,"producter-Thread");
        thread.start();
        new Thread(consumer,"COnsumer-Thread").start(); }}Copy the code

The main function is very simple, we create a public warehouse queue of length 10, we pass it to two threads, we start two threads, and when we start, notice that our consumption has a sleep of 100 milliseconds, then the public warehouse must be filled by the producer and blocked waiting for consumption. When the consumer no longer needs the data, the canceled flag bit is set to true, at which point the producer theoretically breaks out of the while loop and prints “producer run ended.” Although producter. mark is set to false, the producer does not stop because numqueue.put (num) is blocked. There is no way to enter the producter. mark loop until it is woken up, so using volatile will not stop the producer in this case, whereas using interrupt will feel the interrupt signal even if the producer is blocking. And do response processing.

conclusion














This article was published by AnonyStar. It may be reproduced but the original source must be claimed. Admire “the art of elegant coding” firmly believe that practice makes perfect, and strive to change your life