Why not use thread Stop() method

Do not use thread directly There are two reasons for stop ()

  • The execution of the stop() method requires obtaining the lock of the current thread.
  • Once the stop() method is executed, all the locks on the current thread will be released immediately, and the thread will stop immediately, which may lead to data security problems.

The execution of the stop() method requires obtaining the lock of the current thread

Thread. The source code of stop () is as follows. You can see that the native method stop0() will eventually be called.

@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());
}
   private native void stop0(Object o);

At this time, we can't see anything. Let's run an example. In this example, we let the thread that counts and outputs run for 100ms and call its stop method,
As expected, the counting process will stop immediately, and then print an exception. However, the result is that each counting process will be completed, and then the exception will be printed.

public class stopTest {
    public static void main(String[] args) {  
        try {  
            Thread t = new Thread() {  
                public synchronized void run() {  
                    try {  
                        long start=System.currentTimeMillis();  
                        for (int i = 0; i < 100000; i++)  
                            System.out.println("runing.." + i);  
                        System.out.println((System.currentTimeMillis()-start)/1000);  
                    } catch (Throwable ex) {  
                        System.out.println("Caught in run: " + ex);  
                        ex.printStackTrace();  
                    }  
                }  
            };  
            t.start();  
            // Give t time to get going...  
            Thread.sleep(100);  
            t.stop(); // EXPECT COMPILER WARNING  
        } catch (Throwable t) {  
            System.out.println("Caught in main: " + t);  
            t.printStackTrace();  
        }  
  
    }  
}
// The output result is
runing..99994
runing..99995
runing..99996
runing..99997
runing..99998
runing..99999
runing..100000

The reason for the above problems is that the run method of Thread uses synchronized locking, while Thread stop0() also needs to acquire locks to execute. The run method has acquired the lock when it runs, so stop0() is blocked until the lock is released at the end of counting.
Knowing the problem, we modify the lock and use an object as the lock of the thread. final Object lock = new Object(); Use the following code to test

public static void main(String[] args) {  
    final Object lock = new Object();  
    try {  
        Thread t0 = new Thread() {  
            public void run() {  
                try {  
                    synchronized (lock) {  
                        System.out.println("thread->" + getName()  
                                + " acquire lock.");  
                        sleep(3000);// sleep for 3s  
                        System.out.println("thread->" + getName()  
                                + " release lock.");  
                    }  
                } catch (Throwable ex) {  
                    System.out.println("Caught in run: " + ex);  
                    ex.printStackTrace();  
                }  
            }  
        };  

        Thread t1 = new Thread() {  
            public void run() {  
                synchronized (lock) {  
                    System.out.println("thread->" + getName()  
                            + " acquire lock.");  
                }  
            }  
        };  

        t0.start();  
        // Give t time to get going...  
        Thread.sleep(100);  
        //t0.stop();  
        t1.start();  
    } catch (Throwable t) {  
        System.out.println("Caught in main: " + t);  
        t.printStackTrace();  
    }  
}

If you do not call t0 The stop () method, t0 and T1, can operate normally and obtain locks respectively. The output is:

thread->Thread-0 acquire lock.
thread->Thread-0 release lock.
thread->Thread-1 acquire lock.

If you call t0 Stop () method, the output result is

thread->Thread-0 acquire lock.
thread->Thread-1 acquire lock.
Caught in run: java.lang.ThreadDeath
java.lang.ThreadDeath
 at java.lang.Thread.stop(Thread.java:715)
 at com.yezi.test.timeout.ThreadStopTest.main(ThreadStopTest.java:40)

You can see that t0 directly aborts the operation, throws an exception, and releases the lock. This kind of code that can stop running anywhere is unacceptable because the state of the object it returns is unpredictable.
for instance:

For example, the object obj stores a range of values: the minimum value is low, the maximum value is high, and the low value must not be greater than high. This relationship is protected by lock to avoid the relationship failure caused by race conditions during concurrency. Assuming that the current low value is 5 and the high value is 10, when the thread t obtains the lock, it updates the low value to 15 and is stopped. It's really bad. If the Error caused by stop is not captured, the low value is 15 and the high value is 10, which makes the less than relationship between them not guaranteed, that is, the object state is destroyed! If you catch the Error caused by stop when assigning a value to low, you may continue the assignment of the following high variables, but no one knows in which statement the Error will be thrown. If the relationship between object states is more complex? This way is almost impossible to maintain. It's too complicated! If it is an interrupt operation, it is determined not to throw an Error when executing the low assignment, so that the program is controllable for the consistency of object state.
Original address: https://blog.csdn.net/kingzma/article/details/45739963

Tags: Java

Posted by pmzq on Sun, 15 May 2022 19:12:06 +0300