zoukankan      html  css  js  c++  java
  • 为什么不能使用Thread.stop()方法

    不要直接使用Thread.stop()的原因有两点

    • stop() 方法的执行需要获取当前线程的锁。
    • stop() 方法一旦执行,当前线程上所有的锁会被立即释放,而且线程立刻中止,这可能导致数据安全问题。

    stop() 方法的执行需要获取当前线程的锁

    Thread.stop()的源码如下,可以看到最终会调用stop0()这个native方法。

    @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);
    

    此时看不出什么,我们运行一个示例,这个例子中我们让这个数数并输出的线程运行了100ms便调用它的stop方法,
    按照预期,数数的过程会立刻中止,然后打印出异常。然而结果却是每次数数的过程都会执行完成,然后才会打印出异常。

    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();  
            }  
      
        }  
    }
    
    // 输出结果为
    runing..99994
    runing..99995
    runing..99996
    runing..99997
    runing..99998
    runing..99999
    runing..100000
    

    出现以上问题的缘由在于Thread的run方法使用了synchronized加锁了,而Thread.stop0()也同样需要获取锁才能执行。run方法在运行的时候便已经获取了锁,于是stop0()便一直被阻塞住,直到数数结束释放锁。
    知道了问题所在,我们把锁修改一下,使用一个对象来作为线程的锁 final Object lock = new Object(); 使用如下代码来测试

    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();  
        }  
    }
    

    如果没有调用t0.stop()方法,t0,t1可以正常的运行,分别获取锁,输出为:

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

    如果调用了t0.stop()方法,输出结果为

    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.pikzas.test.ThreadStopTest.main(ThreadStopTest.java:40)
    

    可以看到t0直接中止了运行,抛出了异常,并且释放了锁。这种可以在任何地方中止运行的代码是不可接受的,因为它返回的对象状态是不可估计的。

    举个例子:
    我们希望对象保存一对数据i,j。这一对数据能同时候保持自增且两个变量保持相等。

    public class DupValueTest extends Thread {
        public static void main(String[] args) throws InterruptedException {
            DupValueTest test = new DupValueTest();
            test.start();
            Thread.sleep(1000);
            test.stop();
            Thread.sleep(500);
            System.out.println("i: " + i + ", j: " + j);
        }
    
        private static int i, j = 0;
    
        @Override
        public synchronized void run() {
            while (true) {
                i++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                j++;
            }
        }
    }
    
    //输出结果为
    i: 10, j: 9
    

    可以看到在调用stop之后,程序输出的结果是不符合预期的,i j的值变得不相等了,而我们的代码是有保证同步的。这样的运行结果是不能接受的。所以说stop方法不能被用来中止一个线程的运行。
    那么该如何正确得中止一个线程呢?参考线程的中止。
    原文地址:https://blog.csdn.net/kingzma/article/details/45739963

  • 相关阅读:
    触发器_01(trigger)
    24.Show table status解析
    Mysql排名问题
    zabbix监控
    MyFlash工具
    23.Sharding:谁都能读懂的分库、分表、分区
    Mysql集群结构说明
    Percona XtraDB Cluster(PXC) Mysql集群
    mysql-router
    MGR搭建的过程中遇见的错误以及处理方法
  • 原文地址:https://www.cnblogs.com/Pikzas/p/13723488.html
Copyright © 2011-2022 走看看