Stop threads safely and elegantly

First, ask the question, how do you stop threads safely and elegantly?

Behind this problem, it can be as small as simply terminating a Thread thread, or as large as the elegant offline of a Dubbo application... They all have one thing in common, that is, instead of forcibly stopping a process or thread at once, they have the opportunity to clean up resources and run through the remaining tasks during the termination process. Finally, no resources are running until the end is done, which is a safe and elegant stop.

In Java multi-threading, the method of stopping a thread, one of which is out of date and not recommended, stops the thread simply and roughly. It stops without guaranteeing the normal release of the thread's resources, which means that there may still be threads running and ending without running. This can result in an indeterminate state of the program, a deadlock state.

The method of stop ping threads has expired and is no longer recommended.

So is there another way to gracefully end a thread?

Here, this can be achieved indirectly through the interrupt() method.

Why is it simple?

Because the thread executing the interrupt() method does not terminate the thread directly.

Next, let's briefly analyze how interrupt() implements a safe and elegant termination of threads.

First, when a thread's interrupt() method is executed, it is given an interrupt identification property, which is originally false, but when it is identified as a false, it becomes true. This is a bit like the volatile variable's visibility gameplay. With such a visibility variable, we can set a state when that state is satisfied. You can jump out of the program and end early.

The status value of the interrupt identifier property can be obtained by the isInterrupted() method. If true, it means that the thread has been marked with the interrupt identifier, then you can clean up the resources before you end the thread.

One thing to note, however, is that there is a similar static method, Thread.interrupted(), which also gets the thread interrupt state, but unfortunately, this interrupted method resets the thread's interrupt state immediately after determining if a thread is interrupted, restoring the thread to a non-interrupt state. In addition, declaring a method that throws an InterruptedException clears the thread's interrupt identity state through the virtual machine before throwing an exception, then throws the exception, and then calling the isInterrupted() method returns false.

Here's a code check:

public static void main(String[] args) throws InterruptedException {
    Runner one = new Runner();
    Thread countThread = new Thread(one,"CountThread");
    //Start Thread
    countThread.start();
    //Silence for one second, let the thread CountThread execute for one second first
    TimeUnit.SECONDS.sleep(1);
    //Set interrupt identifier on thread countThread by interrupt() method
    countThread.interrupt();
}

private static class Runner implements Runnable {
    private long i;
    private volatile boolean on = true;
    @Override
    public void run() {
        //When the countThread thread identifies an interruption, Thread.currentThread().isInterrupted() returns true to terminate the thread while stopping the continued running of resource i++.
        while (!Thread.currentThread().isInterrupted()){
            i++;
        }
        System.out.println("Count i = " + i);
    }
}

As mentioned earlier, interrupt() identifies the break bit much like the visibility of a volatile variable. Conversely, volatile can somehow replace interrupt() to determine if a thread needs to be interrupted, as shown in the following code:

public static void main(String[] args) throws InterruptedException {
    Runner two = new Runner();
    Thread countThread = new Thread(two,"CountThread");
    countThread.start();
    //Sleep for 1 second
    TimeUnit.SECONDS.sleep(1);
    two.cancel();

}

private static class Runner implements Runnable {
    private long i;
    private volatile boolean on = true;
    @Override
    public void run() {
        while (on){
            i++;
        }
        System.out.println("Count i = " + i);
    }

    public void cancel(){
        on = false;
    }
}

Reference to The Art of Java Concurrent Programming

Tags: Java

Posted on Sat, 04 Dec 2021 13:58:39 -0500 by saunders1989