Thread.stop()为何废弃
程序员文章站
2022-04-01 15:50:34
...
官方给出的说明:
/** @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
异常并修复对象的原因:
- 一个线程几乎可以在任何地方抛出一个
ThreadDeath
异常。考虑到这一点,所有同步的方法和块都必须详细研究。 - 一个线程可以抛出第二个
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()
- 使用
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
*/
- 使用原子类或者
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()
,使用上述的方法替代它。
参考链接: