点击关注公众号,实用技术文章及时了解

 作者:浪舟子

 blog.csdn.net/qq_40400960/article/details/112651249

我们知道像stop、suspend这几种中断或者阻塞线程的方法在较高java版本中已经被标记上了@Deprecated过期标签,那么为什么她们曾经登上了java的历史舞台而又渐渐的推出了舞台呢,到底是人性的扭曲还是道德的沦丧呢,亦或是她们不思进取被取而代之呢,如果是被取而代之,那么取而代之的又是何方人也,本文我们将一探究竟。

一、stop的落幕

首先stop方法的作用是什么呢,用java源码中的一句注释来了解一下:Forces the thread to stop executing.,即强制线程停止执行,'Forces’似乎已经透漏出了stop方法的蛮狠无理。那么我们再看看java开发者是怎们解释stop被淘汰了的:

我们从中可以看出以下几点:

  1. stop这种方法本质上是不安全的

  2. 使用Thread.stop停止线程会导致它解锁所有已锁定的监视器,即直接释放当前线程已经获取到的所有锁,使得当前线程直接进入阻塞状态

我们举例来看一下上边提到的两点:

public static void main(String[] args) throws InterruptedException {Object o1=new Object();Object o2=new Object();Thread t1=new Thread(()->{synchronized (o1){synchronized (o2){try {System.out.println("t1获取到锁");Thread.sleep(5000);System.out.println("t1结束");} catch (InterruptedException e) {e.printStackTrace();}}}});t1.start();Thread.sleep(1000);Thread t2=new Thread(()->{synchronized (o1){synchronized (o2){try {System.out.println("t2获取到锁");Thread.sleep(5000);System.out.println("t2结束");} catch (InterruptedException e) {e.printStackTrace();}}}});t2.start();t1.stop();}

运行结果:

可以看到,当线程t1在获取到o1和o2两个锁开始执行,在还没有执行结束的时候,主线程调用了t1的stop方法中断了t1的执行,释放了t1线程获取到的所有锁,中断后t2获取到了o1和o2锁,开始执行直到结束,而t1却夭折在了sleep的时候,sleep后的代码没有执行。

因此使用stop我们在不知道线程到底运行到了什么地方,暴力的中断了线程,如果sleep后的代码是资源释放、重要业务逻辑等比较重要的代码的话,亦或是其他线程依赖t1线程的运行结果,那直接中断将可能造成很严重的后果。

那么不建议使用stop中断线程我们应该怎么去优雅的结束一个线程呢,我们可以存java开发者的注释中窥探到一种解决方案:

可以看到java开发者推荐我们使用以下两种方法来优雅的停止线程:

1.定义一个变量,由目标线程去不断的检查变量的状态,当变量达到某个状态时停止线程。

代码举例如下:

volatile static boolean flag=false;
public static void main(String[] args) throws InterruptedException {Object o1=new Object();Thread t1=new Thread(()->{synchronized (o1){try {System.out.println("t1获取到锁");while (!flag)Thread.sleep(5000);//执行业务逻辑System.out.println("t1结束");} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();Thread.sleep(1000);Thread t2=new Thread(()->{synchronized (o1){try {System.out.println("t2获取到锁");Thread.sleep(5000);//执行业务逻辑System.out.println("t2结束");} catch (InterruptedException e) {e.printStackTrace();}}});t2.start();flag=true;}

运行结果:

2.使用interrupt方法中断线程。

代码举例如下:

public static void main(String[] args) throws InterruptedException {Object o1=new Object();Thread t1=new Thread(()->{synchronized (o1){System.out.println("t1获取到锁");while (!Thread.currentThread().isInterrupted()) {for (int i = 0; i < 100; i++) {if(i==50)System.out.println();System.out.print(i+" ");}System.out.println();}System.out.println("t1结束");}});t1.start();Thread t2=new Thread(()->{synchronized (o1){try {System.out.println("t2获取到锁");Thread.sleep(5000);//执行业务逻辑System.out.println("t2结束");} catch (InterruptedException e) {e.printStackTrace();}}});t2.start();t1.interrupt();}

运行结果:

我们用while (!Thread.currentThread().isInterrupted())来不断判断当前线程是否被中断,中断的话则让线程自然消亡并释放锁。可以看到调用interrupt方法后并不会像stop那样暴力的中断线程,会等到当前运行的逻辑结束后再检查是否中断,非常的优雅。另外,关注Java知音公众号,回复“后端面试”,送你一份面试题宝典!

注:运行举例代码可能不会打印出数字,这是因为t1线程运行到while(!Thread.currentThread().isInterrupted())时,主线程已经调了interrupt方法,因此多次运行可能会打印出数字。

二、suspend的落幕

suspend方法的作用是挂起某个线程直到调用resume方法来恢复该线程,但是调用了suspend方法后并不会释放被挂起线程获取到的锁,正因如此就给suspend和resume这哥俩贴上了容易引发死锁的标签,当然这也正是导致suspend和resume退出历史舞台的罪魁祸首。同样我们看看java开发者为suspend的淘汰给出的理由:

从中我们可以得出以下结论:

  1. suspend具有天然的死锁倾向

  2. 当某个线程被suspend后,该线程持有的锁不会被释放,其他线程也就不能访问这些资源

  3. suspend某个线程后,如果在resume的过程中出现异常导致resume方法执行失败,则lock无法释放,导致死锁

接下来模拟一下由suspend引起的死锁场景,Talk is cheap,show my code:

public static void main(String[] args) throws InterruptedException {Object o1=new Object();Object o2=new Object();Thread t1=new Thread(()->{synchronized (o1){System.out.println("t1获取到o1锁开始执行");try {Thread.sleep(5000);//模拟执行业务逻辑} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1执行结束");}});t1.start();Thread t2=new Thread(()->{synchronized (o2){System.out.println("t2获取到o2开始执行");try {Thread.sleep(2000);//执行耗时业务} catch (InterruptedException e) {e.printStackTrace();}synchronized (o1){System.out.println("t2获取到o1锁开始继续执行");}System.out.println("t2执行结束");}});t2.start();Thread.sleep(1000);t1.suspend();//假设抛出了一个未知异常int i=1/0;t1.resume();}

运行结果:

可以看到,整个程序卡的死死的,在调用resume恢复t1线程之前抛出了一个未知异常,导致t1一直挂起进而无法释放o1锁,而t2需要获取到o1锁后才能继续执行,但苦苦等待,奈何o1被t1拿捏的死死的,从此整个程序就陷入了无尽的等待中----死锁。

推荐好文

>>【练手项目】基于SpringBoot的ERP系统,自带进销存+财务+生产功能

>>分享一套基于SpringBoot和Vue的企业级中后台开源项目,代码很规范!

>>能挣钱的,开源 SpringBoot 商城系统,功能超全,超漂亮!

为什么强烈不推荐使用stop、suspend方法来中断线程?相关推荐

  1. Java Thead.interrupt 方法没有使线程停止工作

    有问题的interrupt package com.xinyu.test;public class TestInterrupt {public static void main(String[] ar ...

  2. 为什么不推荐使用 stop、suspend 方法中断线程?

    以下文章来源方志朋的博客,回复"666"获面试宝典 作者 | 浪舟子 来源 | https://blog.csdn.net/qq_40400960/article/details/ ...

  3. java 线程resume_为什么java线程不推荐调用stop,suspend,resume方法

    标签: 一.stop stop方法不推荐调用,官方说发是"可能发生不可预测的问题".其实线程在调用stop方法后,会停止自己.线程停止的时候,会直接停止执行,并释放自己正在使用的锁 ...

  4. Java中有几种方法可以实现一个线程??用什么关键字修饰同步方法??stop()和suspend()方法为什么不推荐使用??

    1. Java中有几种方法可以实现一个线程?? 两种,分别是继承thread类和实现Runnable类接口. 第一种: new Thread(){}.start();这表示调用Thread子类对象的r ...

  5. stop() 和 suspend() 方法为何不推荐使用

    http://blog.csdn.net/yakihappy/article/details/3979912 反对使用stop(),是因为它不安全.它会解除由线程获取的所有锁定,当在一个线程对象上调用 ...

  6. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

    答: 1.有两种实现方法,分别是继承Thread类与实现Runnable接口 继承扩展性不强,java总只支持单继承,如果一个类继承Thread就不能继承其他的类了. 2.用synchronized关 ...

  7. 1、为什么使用Long时,推荐多使用valueOf方法,少使用parseLong方法

    为什么使用Long时,推荐多使用valueOf方法,少使用parseLong方法? 因为Long本身有缓存机制,缓存了-128到127范围内的Long,valueOf方法会从缓存中去拿值,如果命中缓存 ...

  8. 十四个值得推荐的个人提升方法

    十四个值得推荐的个人提升方法 文章分类:IT生活      1.每天读书.书是智慧的源泉.你读的书越多,你就会变得更加有智慧.都有什么书可以让你提高自己呢?博华看过的<建立你的时间资本>. ...

  9. 个性化新闻文章推荐的上下文Bandit方法

    个性化新闻文章推荐的上下文Bandit方法 摘要 个性化web服务通过同时使用内容和用户信息,努力使其服务(广告.新闻文章等)适应单个用户.解决这个问题有两个挑战: 首先,web服务的特点是内容池的动 ...

最新文章

  1. python错误代码提示手册_python学习手册笔记——33.异常编码细节
  2. python matplotlib散点图-python matplotlib从函数更新散点图
  3. 新基建数据中心如何建?附建设导则
  4. grub配置文件丢失的情况下修复
  5. c++primer 5th第15章基础、课后习题自己解析、心得体会等
  6. Redis 性能优化的 13 条军规!史上最全
  7. ImmunityDebugger 学习
  8. SQL分组字符串相连
  9. 腾讯地图拾取坐标html,GitHub - cloydlau/coord-picker: 高德/腾讯地图坐标拾取器 / A coordinates picker for amap/tmap...
  10. mongodb官网下载不了, MongoDB下载、安装、配置、使用,如何下载MongoDB数据库,MongoDB入门
  11. FFmpeg —— 13.示例程序(七):视频编码器(YUV编码为H265)
  12. android 一分钟倒计时动画,Android利用属性动画自定义倒计时控件
  13. JavaOJ 汉诺塔问题
  14. 安装 TiDB 分布式数据库
  15. (原创)android6.0系统 PowerManager深入分析
  16. 软件测试人员分工【管理层必看】
  17. 光耦隔离前后电阻阻值选择注意事项
  18. Postman进阶篇动态参数、自定义动态参数及自定义动态参数全局变量断言
  19. Epic Games CEO,《无尽之剑》创始人Tim Sweeney:下一代智能手机和平板电脑的游戏趋势
  20. Flink 中的时间和窗口

热门文章

  1. 有戏!低于4000的iPhone SE2买不买?
  2. 或为红米8A 卢伟冰确认将推出5000mAh新机
  3. 准备好钱了吗?新款iPhone或于9月13日开始接受预订
  4. 《哪吒》票房超25亿元 进入中国电影票房总榜前十
  5. 令人窒息!iPhone充电时自燃烧毁房子,到底是谁的锅?
  6. 1499元!三星Galaxy A40s开启预约:5000mAh大容量电池加持
  7. 收集SQLite中的时间日期函数[ZT]
  8. websocket如何保持连接压力测试统计最后断开了几个链接
  9. INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113
  10. 应用市场中的应用转让