0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用stop、suspend方法来中断线程的坏处在哪?

Android编程精选 来源:CSDN技术社区 作者:浪舟子 2021-07-26 14:23 次阅读

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

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

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

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

使用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();

}

运行结果:

1fb0958c-e009-11eb-9e57-12bb97331649.png

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

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

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

1fdbe836-e009-11eb-9e57-12bb97331649.png

可以看到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;

}

运行结果:

1ffacdc8-e009-11eb-9e57-12bb97331649.png

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();

}

运行结果:

202dbdb4-e009-11eb-9e57-12bb97331649.png

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

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

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

206731fc-e009-11eb-9e57-12bb97331649.png

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

suspend具有天然的死锁倾向

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

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();

}

运行结果:

20736242-e009-11eb-9e57-12bb97331649.png

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

作者丨浪舟子

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

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 中断
    +关注

    关注

    5

    文章

    889

    浏览量

    41217

原文标题:为什么强烈不推荐使用stop、suspend方法来中断线程?

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    AD8338有没有可行的方法来测量大增益?

    AD8338是一款VGA芯片,可变增益范围为-10dB至70dB。然而,理论上的70dB增益过大,导致来自源的输入信号非常小,容易受到干扰,导致70dB增益未得到验证。有没有可行的方法来测量大增益?
    发表于 05-21 07:06

    STM32F107的OTG在stop模式下无法通过EXTI_18唤醒,没有中断产生是怎么回事?

    作为device,想验证EXTI_18的中断,配置好EXTI初始化,但只有在enable suspend int后,在插拔USB线缆时才会进OTG_FS_WKUP_IRQHandler,如果配置设备
    发表于 05-06 08:59

    使用FreeRTOS创建的DHCP线程里面的DHCP是在哪里定义的?

    请教下,使用 FreeRTOS 创建的 DHCP 线程里面的 DHCP 是在哪里定义的,貌似没有找到 ? FreeRTOS 版本 v9.0.0 具体如下: // 创建 DHCP 线程 void
    发表于 04-30 07:34

    stm32外部中断不能唤醒stop休眠模式怎么解决?

    按键引脚设置成外部中断方式,可以正常唤醒stop模式;但是充电口设置成外部中断,却无法唤醒stop休眠!!!配置都是一样的,按键下降沿触发,充电检测是上升沿触发。 有可能是什么原因,
    发表于 04-26 06:11

    如果是使用六步方波的方法来控制电机,要如何实现过电流保护?

    请问一下如果是使用六步方波的方法来控制电机,要如何实现过电流保护? 以免电流过大造成板子损坏
    发表于 04-22 08:10

    PT断线是什么?为什么说PT断线影响很严重?

    PT断线是什么?为什么说PT断线影响很严重? PT断线是指电压互感器的一种故障状态,即PT缺乏或中断了电压信号的传输。PT作为一种重要的电气元件,主要用于将高压系统的电压降到安全范围内
    的头像 发表于 12-26 16:01 2354次阅读

    一种简单的方法来将振荡器相位噪声转换为时间抖动

    电子发烧友网站提供《一种简单的方法来将振荡器相位噪声转换为时间抖动.pdf》资料免费下载
    发表于 11-23 15:15 0次下载
    一种简单的<b class='flag-5'>方法来</b>将振荡器相位噪声转换为时间抖动

    线程同步的几种方法

    线程同步是指在多个线程并发执行的情况下,为了保证线程执行的正确性和一致性,需要采用特定的方法来协调线程之间的执行顺序和共享资源的访问。下面
    的头像 发表于 11-17 14:16 948次阅读

    如何使用硬件FIFO减少接收中断次数

    本文给介绍如何使用带FIFO的串口减少接收中断次数,通过一种自定义通讯协议格式,给出帧打包方法;之后介绍一种特殊的串口数据发送方法,可在避免使用串口发送
    发表于 11-06 12:22 468次阅读
    如何使用硬件FIFO<b class='flag-5'>来</b>减少接收<b class='flag-5'>中断</b>次数

    中断嵌套的好处与坏处有哪些?

    中断嵌套的好处与坏处有哪些
    发表于 10-27 06:44

    STM32如何配置外部中断?STM32外部中断配置步骤

    触发或上升沿触发的外部中断线。这些中断线可以通过中断线控制器(EXTI)进行设置,并可以绑定到不同的GPIO端口上,以实现
    的头像 发表于 10-26 17:47 3010次阅读

    线程间通信的几种方式

    1 使用synchronized,wait,notify,notifyAll 使用synchronized 等方法来控制共享变量,完成交替打印。 思路: 在同步方法中先判断信号量,如果不是当前需要
    的头像 发表于 10-10 16:23 579次阅读
    <b class='flag-5'>线程</b>间通信的几种方式

    QT原生的QJson是否有更优雅的方法来封装一些Json对象

    之前一直用的是cJSON库封装和解析,写久了感觉实在太丑,又难维护,于是还是研究下QT原生的QJson是否有更优雅的方法来封装一些Json对象
    的头像 发表于 10-08 09:26 1088次阅读
    QT原生的QJson是否有更优雅的<b class='flag-5'>方法来</b>封装一些Json对象

    使用MM32F0270 USB从Suspend模式唤醒

    使用MM32F0270 USB从Suspend模式唤醒
    的头像 发表于 09-26 16:39 804次阅读
    使用MM32F0270 USB从<b class='flag-5'>Suspend</b>模式唤醒

    Rust的多线程编程概念和使用方法

    和字段、常见用法以及多线程的一些实践经验。由浅入深带你零基础玩转Rust的多线程编程。 线程的基本概念和使用方法 Thread是Rust中并发编程的一种基本方式。Rust中的Threa
    的头像 发表于 09-20 11:15 808次阅读