众所周知,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方法无法终止你的线程相关推荐

  1. libreportparam2.dll无法继续执行代码_Java并发系列番外(1)——让Thread#stop方法无法终止你的线程...

    众所周知,Thread 类有一个 stop 方法,可以用来终止线程.当然,这个方法连同 suspend,resume 方法一起都已经被弃用了.原因是 stop 方法终止线程过于暴力,不管被 stop ...

  2. java并发编程之thread.join()方法详解

    thread.join()方法的作用:保证线程的执行结果的可见性.原理是通过阻塞主线程实现的. 代码Demo如下: public class ThreadJoinDemo {public static ...

  3. java thread yield()_Java Thread yield()方法

    Java Thread yield()方法 java.lang.Thread.yield() 方法使当前执行的线程对象来暂停并允许其他线程执行. 1 语法 public static void yie ...

  4. Java并发 正确终止与恢复线程

    为什么80%的码农都做不了架构师?>>>    前面提到了stop().suspend()等方法在终止与恢复线程的弊端,那么问题来了,应该如何正确终止与恢复线程呢?这里可以使用两种方 ...

  5. java thread exit方法_实例分析Java终止线程和stop()方法

    Java终止线程实例和stop()方法源码阅读 了解线程 概念 线程 是程序中的执行线程.Java 虚拟机允许应用程序并发地运行多个执行线程. 线程特点 拥有状态,表示线程的状态,同一时刻中,JVM中 ...

  6. 从一道面试题分析Thread.interrupt方法

    阿里面试题: public class TestThread {public static void main(String[] args) {Thread t1 = new Thread() {@O ...

  7. 黑马程序员--线程之间的通信,等待与唤醒机制,线程的终止方式,线程中的其他方法,优先级,toString() 守护线程,GUI图形化界面

    ------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS ...

  8. 高并发编程-Thread#join方法的使用及使用场景分析

    文章目录 含义 方法及示例 void join() void join(long millis) join(long millis, int nanos) 使用场景分析 含义 翻看下源码的注释: Wa ...

  9. java threadgourp_Java Thread getThreadGroup()方法

    Java Thread getThreadGroup()方法 java.lang.Thread.getThreadGroup() 方法返回此线程所属的线程组.它返回null,如果该线程已经死亡(停止) ...

  10. Java并发编程—Thread类的start()方法是如何启动一个线程的?

    目录 一:Java线程介绍 二:Java线程入口分析 三:Java线程的创建 四:总结 周末抽了点时间,研究了下HotSpot是如何创建Java线程的,顺便总结一下.文中引用的源码里删除很多细节,只保 ...

最新文章

  1. 经典网络LeNet-5介绍及代码测试(Caffe, MNIST, C++)
  2. C语言按两个字节读写二进制文件,C语言 读写二进制文件(示例代码)
  3. php 点击按钮更新mysql_PHP与mysql超链接 有更新按钮 跳转更新,删除后数据表中的数据 怎么做来着?...
  4. 数据结构特性解析 (一) 数组
  5. 【MM模块】Subcontracting 委外加工(外包)—1
  6. dac解码芯片天梯_【关于AK4499引发的思考】选DAC,解码芯片追新有没有必要?
  7. python淘宝抢购_Python 实现毫秒级淘宝抢购脚本的示例代码
  8. click()和onclick()的区别
  9. extend the gridview control
  10. android得到assets下面的资源
  11. UVA10624 Super Number【DFS】
  12. Java调用Lua(转)
  13. 与网络计算机相比,和通信网络相比,计算机网络最本质的功能是什么
  14. adminlte中datatable中自定义搜索和导出按钮
  15. Apache HBase 最新发布2.0.4 ,分布式数据库
  16. URL地址相对路径转绝对路径
  17. android实现标题栏弹框,Android:Dialog对话框、Builder、showDialog、模板方法设计模式...
  18. java csv tab分隔,CSV格式与tab制表符分割的格式文件相互转换,支持管道操作
  19. 项目启动报 JDBC Driver has been forcibly unregistered
  20. 11 空间平面方程 : 参数方程、向量式方程、行列式方程、三点式方程、点法式方程、一般方程

热门文章

  1. Coursera 申请助学金流程和材料
  2. 天涯上令人肝肠寸断的100个经典签名
  3. 测试网站速度简单方法
  4. Linux——vim使用及账号用户管理
  5. PDF文件怎么拆分,PDF拆分技巧
  6. 创灵原始与鸿蒙,上古启示录
  7. goodFeaturesToTrack——Shi-Tomasi角点检测
  8. P61 浮点数、定点数、位类型讲解
  9. Nefu 锐格c实验8
  10. 使用80percent开发rails程序:gem的了解。(kaminari)