This thread termination will lead to service downtime?

Before we start, let's look at 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("子线程开始执行");
                // 模拟业务处理
                Thread.sleep(1000);
            } catch (Exception e) { }
            // 伪代码:重要的业务方法
            System.out.println("子线程的重要业务方法");
        });
        t1.start();
        // 让子线程先运行一点业务
        Thread.sleep(100);
        // 终止子线程
        t1.stop();
        // 等待一段时间,确保子线程“执行完”
        Thread.sleep(3000);
        System.out.println("主线程执行完成");
    }
}

You may have found that the above code uses thread Stop () to terminate the thread. This is not allowed in Java programs. what? Why can't you ask?

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

what? You don't believe it. Look at this picture:

Well, why not? Do you have to give me a perfunctory reason?

Problem 1: it destroys the integrity of the program

In fact, as for the code at the beginning of the article, its execution result is:

We found an amazing problem. The most important pseudo code was not executed, as shown in the figure below:

It can be seen that after using stop() to terminate the thread, the remaining part of the code of the thread will give up execution, which will cause a serious and difficult to find shocking bug. If the code that is not executed is the code that releases system resources or the main logic processing code of the program. This destroys the integrity of the basic logic of the program and leads to unexpected problems. Moreover, it is very secret and difficult to be found and repaired.

Some people say that it's not easy. Don't I just add finally?

What's this??? There are bars everywhere, especially this year.

OK, since this can't convince you, let's go on.

Problem 2: it destroys atomic logic

We know that synchronized is an exclusive reentrant pessimistic lock in Java. If we use it to modify the code, there is no problem with proper multithreading, but if we encounter the stop () method, it is not necessarily. Let's look at the code directly.

public class ThreadStopExample {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread t2 = new Thread(myThread);
        // 开启线程
        t2.start();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(myThread);
            t.start();
        }
        // 结束线程
        t2.stop();
    }

    /**
     * 自定义原子测试线程
     */
    static class MyThread implements Runnable {
        // 计数器
        int num = 0;

        @Override
        public void run() {
            // 同步代码块,保证原子操作
            synchronized (MyThread.class) {
                // 自增
                num++;
                try {
                    // 线程休眠 0.1 秒
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 自减
                num--;
                System.out.println(Thread.currentThread().getName() + " | num=" + num);
            }
        }
    }
}

The results of the above procedures are:

It can be seen from the results that the above code has been modified by synchronized + + and -- operations, and the final printed result num is not 0, but 1.

This is because the stop () method will release all locks in this thread, resulting in program execution disorder and destroying the atomic operation logic of the program.

The above problems lead to the JDK abandoning the stop() method. Its abandoned 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
 * @deprecated 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
 *       <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() {
    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());
}

It can be seen that the stop () method is modified by the @ deprecated annotation, and the code modified by this annotation represents an obsolete method and is not recommended to be used. As can be seen from the remarks of stop (), the official does not recommend using stop (), saying that it is a non secure method.

Thread terminated correctly

How do I terminate a thread? Here are 2 correct methods:

1. User defined exit ID

We can customize a boolean variable to identify whether to exit the thread. The implementation code is as follows:

// 自定义退出标识退出线程
static class FlagThread extends Thread {
    public volatile boolean exit = false;

    public void run() {
        while (!exit) {
            // 执行正常的业务逻辑
        }
    }
}

It can be seen that we use the keyword volatile to modify the thread, so as to ensure the safe execution of multiple threads. When we need to exit the thread, we only need to assign the variable exit to true.

2. Interrupt thread termination

When we use the interrupt () method, the execution results of the above two examples are normal, and the execution code is as follows:

public class ThreadStopExample {
    public static void main(String[] args) throws InterruptedException {
        // 问题一:破坏了程序的完整性
        Thread t1 = new Thread(() -> {
            try {
                System.out.println("子线程开始执行");
                // 模拟业务处理
                Thread.sleep(1000);
            } catch (Exception e) { }
            // 伪代码:重要业务方法
            System.out.println("子线程的重要业务方法");
        });
        t1.start();
        // 让子线程先运行一点业务
        Thread.sleep(100);
        // 终止子线程
        t1.interrupt();
        // 等待一段时间,确保子线程“执行完”
        Thread.sleep(3000);
        System.out.println("主线程执行完成");

        // 问题二:破坏了原子逻辑
        MyThread myThread = new MyThread();
        Thread t2 = new Thread(myThread);
        // 开启线程
        t2.start();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(myThread);
            t.start();
        }
        // 结束线程
        t2.interrupt();
    }

    /**
     * 自定义原子测试线程
     */
    static class MyThread implements Runnable {
        // 计数器
        int num = 0;

        @Override
        public void run() {
            // 同步代码块,保证原子操作
            synchronized (MyThread.class) {
                // 自增
                num++;
                try {
                    // 线程休眠 0.1 秒
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(e.getMessage());
                }
                // 自减
                num--;
                System.out.println(Thread.currentThread().getName() + " | num=" + num);
            }
        }
    }
}

The results of the above procedures are:

It can be seen that the above execution meets our expectations, which is the correct way to terminate the thread.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>