Before we start, what’s wrong with the following code?

public class ThreadStopExample {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                System.out.println("Child thread starts execution");
                // Simulate business processing
                Thread.sleep(1000);
            } catch (Exception e) { }
            // Pseudocode: important business method
            System.out.println("Important business methods for child threads");
        });
        t1.start();
        // Let the subroutine run a little service first
        Thread.sleep(100);
        // Terminate the child thread
        t1.stop();
        // Wait a while to make sure the child thread "executes."
        Thread.sleep(3000);
        System.out.println("Main thread execution completed"); }}Copy the code

As you may have noticed, the above code uses thread.stop () to terminate a Thread, which is not allowed in Java programs. What? Why not, you ask?

First of all, the IDE will despise you. It will prevent you from using thread.stop ()!

What? You don’t believe it. So look at this picture:

Okay, so why can’t you use it like this? You have to give me a perfunctory reason, right?

Problem 1: Breaking the integrity of the program

In fact, in the case of the code at the beginning of the article, the result is:

The child thread starts execution

Main thread execution is complete

We found a huge problem. The most important piece of pseudocode was not executed, as shown below:

You can see that after stopping a thread with stop(), the rest of the thread’s code abandons. this can cause serious and undetectable bugs if the code that is not executed is the code that frees up system resources or is the primary logical processing code for the program. This breaks the integrity of the basic logic of the program, leading to unexpected problems, and it is also very hidden, not easy to find and fix.

Some people say, this is not easy, I add a finally is not finished?

This??? Bar fine everywhere, this year especially many.

Okay, well, if that doesn’t convince you, let’s move on.

Problem two: Breaking atomic logic

We know that synchronized is exclusive reentrant pessimistic lock in Java, which is fine if we use it to modify code, but not if we use stop(), so let’s look at the code.

public class ThreadStopExample {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread t2 = new Thread(myThread);
        // Start the thread
        t2.start();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(myThread);
            t.start();
        }
        // End the thread
        t2.stop();
    }

    /** * Custom atomic test thread */
    static class MyThread implements Runnable {
        / / counter
        int num = 0;

        @Override
        public void run(a) {
            // Synchronize code blocks to ensure atomic operations
            synchronized (MyThread.class) {
                / / since the increase
                num++;
                try {
                    // Thread sleep for 0.1 seconds
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                / / the decrement
                num--;
                System.out.println(Thread.currentThread().getName() + " | num="+ num); }}}}Copy the code

The execution results of the above procedures are:

Thread-5 | num=1

Thread-4 | num=1

Thread-2 | num=1

Thread-1 | num=1

Thread-8 | num=1

Thread-6 | num=1

Thread-9 | num=1

Thread-3 | num=1

Thread-7 | num=1

Thread-10 | num=1

As a result, num is printed as 1 instead of 0 after the synchronized ++ and — operations.

This is because the stop() method releases all locks in the thread, causing the program to execute unsmoothly and breaking the atomic operation logic of the program.

For these reasons, the JDK deprecated the stop() method. The deprecated source code is as follows:

/** * Forces the thread to stop executing. * <p> * If there is a security manager installed, its <code>checkAccess</code> * method is called with <code>this</code> * as its argument. This may result in a * <code>SecurityException</code> being raised (in the current thread). * <p> * If this thread is different from the current thread (that is, the current * thread is trying to stop a thread other than itself), the * security manager's <code>checkPermission</code> method (with a * <code>RuntimePermission("stopThread")</code> argument) is called in * addition. * Again, this may result in throwing a * <code>SecurityException</code> (in the current thread). * <p> * The thread represented by this thread is forced to stop whatever * it is doing abnormally and to throw a newly created * <code>ThreadDeath</code> object as an exception. * <p> * It is permitted to stop a thread that has not yet been started.  * If the thread is eventually started, it immediately terminates. * <p> * An application should not normally try to catch * <code>ThreadDeath</code> unless it must do some extraordinary * cleanup operation (note that the throwing of * <code>ThreadDeath</code> causes <code>finally</code> clauses of * <code>try</code> statements to be executed before the thread * officially dies). If a <code>catch</code> clause catches a * <code>ThreadDeath</code> object, it is important to rethrow the * object so that the thread actually dies. * <p> * The top-level error handler that reacts to otherwise uncaught * exceptions does not print out a message or otherwise notify the * application if the uncaught exception is an instance of * <code>ThreadDeath</code>. * *@exception  SecurityException  if the current thread cannot
 *               modify this thread.
 * @see        #interrupt()
 * @see        #checkAccess()
 * @see        #run()
 * @see        #start()
 * @see        ThreadDeath
 * @see        ThreadGroup#uncaughtException(Thread,Throwable)
 * @see        SecurityManager#checkAccess(Thread)
 * @see        SecurityManager#checkPermission
 * @deprecatedThis 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 * <code>ThreadDeath</code> 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 <code>stop</code> 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 <code>interrupt</code> method should be used to * interrupt the wait. * For more information, see * <a href="{@docRoot} /.. /technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated? </a>. */
@Deprecated
public final void stop(a) {
    SecurityManager security = System.getSecurityManager();
    if(security ! =null) {
        checkAccess();
        if (this != Thread.currentThread()) {
            security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
        }
    }
    // A zero status value corresponds to "NEW", it can't change to
    // not-NEW because we hold the lock.
    if(threadStatus ! =0) {
        resume(); // Wake up thread if it was suspended; no-op otherwise
    }

    // The VM can handle all thread states
    stop0(new ThreadDeath());
}
Copy the code

You can see that the stop() method is Deprecated by the @deprecated annotation, and code that is Deprecated by this annotation is represented as an outdated method and is not recommended for use. As you can see from the note to stop(), the authorities also discourage the use of stop(), saying it is an unsafe method.

Terminate threads correctly

So how do you terminate the thread? Here are two correct ways to do this:

  1. Exit the thread by setting the exit flag;
  2. useinterrupt()Method terminates the thread.

1. Customize the exit identifier

We can define a Boolean variable to indicate whether we need to exit the thread, as follows:

// Exit the thread with a custom exit identifier
static class FlagThread extends Thread {
    public volatile boolean exit = false;

    public void run(a) {
        while(! exit) {// Execute normal business logic}}}Copy the code

As you can see, we use the keyword volatile to make threads safe to execute. If we want the thread to exit, we only need to assign the value of exit to true.

2. Interrupt the thread

Both examples work fine when we use the interrupt() method. The execution code looks like this:

public class ThreadStopExample {
    public static void main(String[] args) throws InterruptedException {
        // Problem 1: Breaking the integrity of the program
        Thread t1 = new Thread(() -> {
            try {
                System.out.println("Child thread starts execution");
                // Simulate business processing
                Thread.sleep(1000);
            } catch (Exception e) { }
            // Pseudocode: important business method
            System.out.println("Important business methods for child threads");
        });
        t1.start();
        // Let the subroutine run a little service first
        Thread.sleep(100);
        // Terminate the child thread
        t1.interrupt();
        // Wait a while to make sure the child thread "executes."
        Thread.sleep(3000);
        System.out.println("Main thread execution completed");

        // Problem 2: breaking atomic logic
        MyThread myThread = new MyThread();
        Thread t2 = new Thread(myThread);
        // Start the thread
        t2.start();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(myThread);
            t.start();
        }
        // End the thread
        t2.interrupt();
    }

    /** * Custom atomic test thread */
    static class MyThread implements Runnable {
        / / counter
        int num = 0;

        @Override
        public void run(a) {
            // Synchronize code blocks to ensure atomic operations
            synchronized (MyThread.class) {
                / / since the increase
                num++;
                try {
                    // Thread sleep for 0.1 seconds
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(e.getMessage());
                }
                / / the decrement
                num--;
                System.out.println(Thread.currentThread().getName() + " | num="+ num); }}}}Copy the code

The execution results of the above procedures are:

The child thread starts execution

Important business methods for child threads

Main thread execution is complete

sleep interrupted

Thread-1 | num=0

Thread-9 | num=0

Thread-10 | num=0

Thread-7 | num=0

Thread-6 | num=0

Thread-5 | num=0

Thread-4 | num=0

Thread-2 | num=0

Thread-3 | num=0

Thread-11 | num=0

Thread-8 | num=0

As you can see, the above execution is in line with our expectations, which is the correct way to terminate the thread.

conclusion

In this article, we’ve looked at three ways a thread can terminate: by customizing the exit flag, by using stop(), or by using interrupt(). While stop() causes problems with integrity and atomicity, and is not recommended by the JDK as an expired method, interrupt() is the most suitable method for terminating threads.

For more exciting content, please follow the wechat official account “Java Chinese Community”