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

    文章

    913

    浏览量

    43566

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

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

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    线程的系统

    线程系统的事件响应也是在中断中完成的,但事件的处理是在线程中完成的。在多线程系统中,线程中断
    发表于 12-08 07:55

    Linux多线程对比单线程的优势

    ,而单线程则需要通过进程间通信实现。「上下文切换开销小」:线程的上下文切换比进程小,因为它们共享相同的地址空间。「提高响应性」:多线程可以使程序更加响应用户输入或其他事件,避免阻塞。
    发表于 12-01 06:11

    切换线程中断被屏蔽怎么解决?

    退出,已经切换到main线程,但是发现此时中断是被屏蔽的。 跟代码发现rt_schedule最后切换线程时是先调用rt_hw_context_switch,再
    发表于 09-29 07:48

    ulog输出异常-中断线程打印冲突怎么解决?

    逻辑:can收到数据后,can中断打印test,并把数据放到消息队列,main函数的消息队列打印消息内容 问题:只要can中断中有test打印的代码,整个串口就会卡死; 中断中无test打印的代码
    发表于 09-28 11:44

    rt_sem_take卡住导致线程无法正常运行怎么解决?

    串口接收数据后release信号量,接收线程take sem,高频大数据量接受数据,运行一段时间后接受线程suspend,但是release正常释放 出现问题问题后查看信息如下: 接受线程
    发表于 09-23 08:17

    想在rtsmart中使用uart2,是不是只能通过修改设备树方法来实现uart2的复用呀?

    我想在rtsmart中使用uart2,是不是只能通过修改设备树方法来实现uart2的复用呀? 修改设备树后如何只编译设备树文件? 编译生成的文件可以直接替换到庐山派里吗,具体替换路径在哪里呀?
    发表于 06-24 07:04

    第六章 外部中断

    本章介绍W55MH32的IO口作为外部中断输入的使用。先阐述了NVIC(嵌套向量中断控制器) 的结构、寄存器、优先级及相关函数,再说明EXTI(外部中断和事件控制器)的功能。框图及IO口与
    的头像 发表于 05-26 16:27 1007次阅读
    第六章 外部<b class='flag-5'>中断</b>

    STM32U5 IWDG的提前唤醒中断无法在STOP模式下触发怎么解决?

    我使用的是STM32U585系列芯片,开启了IWDG,并在运行模式下测试提前唤醒中断正常触发,但在进入STOP2模式后,提前唤醒中断无法触发导致无法喂狗,看门狗超时后芯片复位。 手册中写道IWDG
    发表于 04-27 08:05

    STM32U5 IWDG的提前唤醒中断无法在STOP模式下触发怎么解决?

    我使用的是STM32U585系列芯片,开启了IWDG,并在运行模式下测试提前唤醒中断正常触发,但在进入STOP2模式后,提前唤醒中断无法触发导致无法喂狗,看门狗超时后芯片复位。 手册中写道IWDG
    发表于 04-24 07:50

    使用ad9467-250采集低频信号,请问有什么方法来提高sfdr吗?

    你好,我现在在使用ad9467-250采集低频信号,在测试3Mhz部分时sfdr只有86,采样频率是102.4Mhz,请问有什么方法来提高sfdr吗
    发表于 04-24 06:05

    STM32U5 IWDG的提前唤醒中断无法在STOP模式下触发怎么解决?

    我使用的是STM32U585系列芯片,开启了IWDG,并在运行模式下测试提前唤醒中断正常触发,但在进入STOP2模式后,提前唤醒中断无法触发导致无法喂狗,看门狗超时后芯片复位。 手册中写道IWDG
    发表于 04-22 08:14

    Stm32f103 hal库如果设置多个外部中断,只要用螺丝刀碰触其中一个中断线,所有的中断函数都有可能进入,乱跳,为什么?

    Stm32f103 hal库如果设置多个外部中断,只要用螺丝刀碰触其中一个中断线,所有的中断函数都有可能进入,乱跳。同一个线路板用标准库就没问题。正点原子的开发版及HAL库例程也这样。STM32H562开发板及HAL库例程也这样
    发表于 03-10 08:07

    PTD08A010W想把1.8V的输出通过软件编程的方法来改成3.3V的输出,怎么实现?

    我现在在用VC707FPGA开发板,上面用到了PTD08A010W这款电源芯片,这里提供的是12V转1.8V的功能,但现在我想把1.8V的输出通过软件编程的方法来改成3.3V的输出,请问有谁可以提供具体的帮助吗?下面是实际的电路以及电路原理图,我要调的电压为VADJ_FPGA:
    发表于 03-03 07:55

    用ADS1258做了一块采集卡,请问有比较简单的测试方法来测试我的采集卡的性能和精度吗?

    您好!我现在用ADS1258做了一块采集卡,请问有比较简单的测试方法来测试我的采集卡的性能和精度吗。 我现在用普通的信号发生器产生了一个正弦波,1KHz的频率,用采集卡采集了16*1024个数
    发表于 02-10 07:49

    程序中断的100种写法

    在编程中,实现程序中断的方式取决于所使用的编程语言、硬件平台以及具体的应用需求。虽然没有100种独立的中断实现方式,但可以通过不同的方法和技术实现
    发表于 01-28 08:25