让Thread#stop方法无法终止你的线程
众所周知,Thread 类有一个 stop 方法,可以用来终止线程。当然,这个方法连同 suspend,resume 方法一起都已经被弃用了。原因是 stop 方法终止线程过于暴力,不管被 stop 的线程在干什么,一旦被 stop 它就得立刻停止执行,然后释放锁,这是非常不安全的。
那么,有没有办法,让被 stop 的线程继续执行,并且不释放锁呢?
我写了一段代码,各位可以拿去试试:
package per.lvjc.concurrent.stop;public class CanNotStopThread extends Thread {private static final Object monitor = new Object();private boolean success = false;int sum = 0;@Overridepublic void run() {synchronized (monitor) {while (!success) {try {rollback();work();System.out.println("sum = " + sum);success = true;} catch (ThreadDeath threadDeath) {//do nothing}}}}private void rollback() {System.out.println("rollback");this.sum = 0;}/* 累加 1~100 */private void work() {int i = 1;while (i < 101) {try {sleep(100);} catch (InterruptedException e) {System.out.println("What the fuck?");}System.out.println("i = " + i);sum += i++;}}public static void main(String[] args) throws InterruptedException {CanNotStopThread canNotStopThread = new CanNotStopThread();Thread thread = new Thread(() -> {synchronized (monitor) {System.out.println("acquired lock");}});canNotStopThread.start();sleep(1000);thread.start();for (int i = 0; i < 100; i++) {canNotStopThread.stop();sleep(100);}}
}
主要逻辑:
- 先开一个线程
canNotStopThread
,它的工作很简单,加锁,然后累加 1~100; - 再开一个线程
thread
,它一直在等canNotStopThread
释放锁; - 最后,在主线程,循环调用
stop
方法 100 次,试图终止canNotStopThread
执行,让thread
获得锁。
这段代码不管跑多少次,都会看到如下结果:
...
rollback
rollback
rollback
rollback
i = 1
i = 2
...
i = 98
i = 99
i = 100
sum = 5050
acquired lockProcess finished with exit code 0
反应了几点:
- 主线程 stop 了 100 次,但是没有起作用;
canNotStopThread
线程还是正确地累加了 1~100;canNotStopThread
线程累加完毕之前,thread
线程休想得到锁,stop 也没用。
stop 方法是否能让线程终止,并且释放锁?
当然能,不用怀疑。
我的这段代码,如果把 while 循环去掉,结果就会变成这样:
rollback
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
acquired lockProcess finished with exit code 0
没有执行完,线程被终止,然后锁丢了。
让 stop 方法不能终止线程的关键是什么?
是那个 while 循环吗?不完全是。
关键点有三个:
- catch
ThreadDeath
(这是个 Error),并且别抛出去,直接吃掉; - catch 块一行代码都不要有,如果有 finally 块,也是一行代码都不要有,只要有代码就必须 catch
ThreadDeath
吃掉; - 来一个循环,业务流程不执行完,不要让它停下来。
为什么要吃掉 ThreadDeath?
如果你的线程被 stop 了,不管你的线程执行到了什么地方,都会立刻抛出一个 ThreadDeath。线程的 run 方法抛了 Error,线程自然就结束了,锁自然也释放了。
所以 ThreadDeath 必须要吃掉,不能让它抛出去,抛出去线程就结束了。
为什么 catch 块和 finally 块不能有代码?
试试把 run 方法改成这样:
@Overridepublic void run() {synchronized (monitor) {while (!success) {try {rollback();work();System.out.println("sum = " + sum);success = true;} catch (ThreadDeath threadDeath) {System.out.println("catch");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}
或者这样:
@Overridepublic void run() {synchronized (monitor) {while (!success) {try {rollback();work();System.out.println("sum = " + sum);success = true;} catch (ThreadDeath threadDeath) {System.out.println("catch");} finally {System.out.println("finally");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}
这样线程就会被 stop 掉。
如果一定要在 catch 或者 finally 块里面加一些代码,比如打个日志什么的,就必须再套一层 catch:
@Overridepublic void run() {synchronized (monitor) {while (!success) {try {rollback();work();System.out.println("sum = " + sum);success = true;} catch (ThreadDeath threadDeath) {//do nothingtry {System.out.println("catch");} catch (ThreadDeath e) {}} finally {try {System.out.println("finally");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}} catch (ThreadDeath threadDeath) {}}}}}
因为你无法知道,当你的线程被 stop 的时候,它跑到哪了。如果正跑着 try 块的代码,那就没问题;如果在跑 catch 或者 finally 块代码的时候被 stop,就完蛋了。
所以,每一行代码都必须被 try 包起来,catch ThreadDeath
吃掉。因为每一行代码,准确地说,每一条指令都有抛 Error 的风险。
以上,知道了 stop 方法是如何终止线程的,就有办法让它终止不掉你的线程。
当然,这个只能说是一点有意思的奇技淫巧,没什么用啊,不建议这么搞。
让Thread#stop方法无法终止你的线程相关推荐
- libreportparam2.dll无法继续执行代码_Java并发系列番外(1)——让Thread#stop方法无法终止你的线程...
众所周知,Thread 类有一个 stop 方法,可以用来终止线程.当然,这个方法连同 suspend,resume 方法一起都已经被弃用了.原因是 stop 方法终止线程过于暴力,不管被 stop ...
- java并发编程之thread.join()方法详解
thread.join()方法的作用:保证线程的执行结果的可见性.原理是通过阻塞主线程实现的. 代码Demo如下: public class ThreadJoinDemo {public static ...
- java thread yield()_Java Thread yield()方法
Java Thread yield()方法 java.lang.Thread.yield() 方法使当前执行的线程对象来暂停并允许其他线程执行. 1 语法 public static void yie ...
- Java并发 正确终止与恢复线程
为什么80%的码农都做不了架构师?>>> 前面提到了stop().suspend()等方法在终止与恢复线程的弊端,那么问题来了,应该如何正确终止与恢复线程呢?这里可以使用两种方 ...
- java thread exit方法_实例分析Java终止线程和stop()方法
Java终止线程实例和stop()方法源码阅读 了解线程 概念 线程 是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 线程特点 拥有状态,表示线程的状态,同一时刻中,JVM中 ...
- 从一道面试题分析Thread.interrupt方法
阿里面试题: public class TestThread {public static void main(String[] args) {Thread t1 = new Thread() {@O ...
- 黑马程序员--线程之间的通信,等待与唤醒机制,线程的终止方式,线程中的其他方法,优先级,toString() 守护线程,GUI图形化界面
------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS ...
- 高并发编程-Thread#join方法的使用及使用场景分析
文章目录 含义 方法及示例 void join() void join(long millis) join(long millis, int nanos) 使用场景分析 含义 翻看下源码的注释: Wa ...
- java threadgourp_Java Thread getThreadGroup()方法
Java Thread getThreadGroup()方法 java.lang.Thread.getThreadGroup() 方法返回此线程所属的线程组.它返回null,如果该线程已经死亡(停止) ...
- Java并发编程—Thread类的start()方法是如何启动一个线程的?
目录 一:Java线程介绍 二:Java线程入口分析 三:Java线程的创建 四:总结 周末抽了点时间,研究了下HotSpot是如何创建Java线程的,顺便总结一下.文中引用的源码里删除很多细节,只保 ...
最新文章
- 经典网络LeNet-5介绍及代码测试(Caffe, MNIST, C++)
- C语言按两个字节读写二进制文件,C语言 读写二进制文件(示例代码)
- php 点击按钮更新mysql_PHP与mysql超链接 有更新按钮 跳转更新,删除后数据表中的数据 怎么做来着?...
- 数据结构特性解析 (一) 数组
- 【MM模块】Subcontracting 委外加工(外包)—1
- dac解码芯片天梯_【关于AK4499引发的思考】选DAC,解码芯片追新有没有必要?
- python淘宝抢购_Python 实现毫秒级淘宝抢购脚本的示例代码
- click()和onclick()的区别
- extend the gridview control
- android得到assets下面的资源
- UVA10624 Super Number【DFS】
- Java调用Lua(转)
- 与网络计算机相比,和通信网络相比,计算机网络最本质的功能是什么
- adminlte中datatable中自定义搜索和导出按钮
- Apache HBase 最新发布2.0.4 ,分布式数据库
- URL地址相对路径转绝对路径
- android实现标题栏弹框,Android:Dialog对话框、Builder、showDialog、模板方法设计模式...
- java csv tab分隔,CSV格式与tab制表符分割的格式文件相互转换,支持管道操作
- 项目启动报 JDBC Driver has been forcibly unregistered
- 11 空间平面方程 : 参数方程、向量式方程、行列式方程、三点式方程、点法式方程、一般方程