Thread.stop()为何废弃

官方给出的说明:

/** @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>.
  */

从注释可以看出使用Thread.stop()停掉一个线程将会导致所有已锁定的监听器被解锁(解锁的原因是当threaddeath异常在堆栈中传播时,监视器被解锁),这个之前被监听器锁定的对象被解锁,其他线程就能随意操作这个对象,将导致任何可能的结果。

官方给出的网页说明了不能捕获ThreadDeath异常并修复对象的原因:

  1. 一个线程几乎可以在任何地方抛出一个ThreadDeath异常。考虑到这一点,所有同步的方法和块都必须详细研究。
  2. 一个线程可以抛出第二个ThreadDeath异常,同时从第一个线程清除(在catch或finally子句中)。清理将不得不重复,直到它成功。确保这一点的代码将非常复杂。

所以捕获ThreadDeath异常是不可取的。

下面给出一个例子说明Thread.stop()将导致所有已锁定的监听器被解锁

public class StopTest {
    public static void main(String[] args) {
        final Object lock = new Object();

        try {
            Thread t0 = new Thread(() -> {
                try {
                    synchronized (lock) {
                        System.out.println("thread->" + Thread.currentThread().getName()
                                + " acquire lock.");
                        // sleep for 3s
                        Thread.sleep(3000);
                        System.out.println("thread->" + Thread.currentThread().getName()
                                + " release lock.");
                    }
                } catch (Throwable ex) {
                    System.out.println("Caught in run: " + ex);
                    ex.printStackTrace();
                }
            });

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

            t0.start();
//            Thread.sleep(1000);
//            t0.stop();
            t1.start();
        } catch (Throwable e) {
            System.out.println("Caught in main: " + e);
            e.printStackTrace();
        }
    }
}

两个线程需要使用同一个对象,一开始lock被t0持有,经过三秒被t1持有,所以如果正常执行的话结果是这样的

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

但如果把两句注释的语句加上,一开始lock被t0持有,一秒后t0使用了stop结束线程,这个时候t0将会释放lock,所以t1持有了lock,此时,t0继续尝试操作,就会抛出ThreadDeath,结果如下

thread->Thread-0 acquire lock.
java.lang.ThreadDeath
Caught in run: java.lang.ThreadDeath
    at java.lang.Thread.stop(Thread.java:853)
thread->Thread-1 acquire lock.
    at com.minsming.www.StopTest.main(StopTest.java:40)

使用其他方法来替代Thread.stop()

  1. 使用interrupt
public class InterruptTest {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("thread->" + Thread.currentThread().getName()
                        + " run");
            }
            System.out.println("thread->" + Thread.currentThread().getName()
                    + " stop");
        });
        thread.start();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }
}
/* 
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 stop
*/
  1. 使用原子类或者volatile
public class StopTest2 {
    private static AtomicBoolean running = new AtomicBoolean(true);

    public static void main(String[] args) {
        try {
            Thread t0 = new Thread(() -> {
                while (StopTest2.running.get()) {
                    System.out.println("thread->" + Thread.currentThread().getName()
                            + " run");
                }
                System.out.println("thread->" + Thread.currentThread().getName()+  " stop");
            });

            t0.start();
            Thread.sleep(1000);
            StopTest2.running.set(false);
        } catch (Throwable t) {
            System.out.println("Caught in main: " + t);
            t.printStackTrace();
        }
    }
}
/*
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 run
thread->Thread-0 stop
*/

使用Thread.stop()会出现数据不同步,物理资源没及时关闭等危险,所以应该不用Thread.stop(),使用上述的方法替代它。

参考链接:

  1. http://www.baeldung.com/java-thread-stop
  2. https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
  3. http://roomfourteen224.iteye.com/blog/2191890
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值