我们知道像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();
}
运行结果:
可以看到,当线程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的淘汰给出的理由:
从中我们可以得出以下结论:
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();
}
运行结果:
可以看到,整个程序卡的死死的,在调用resume恢复t1线程之前抛出了一个未知异常,导致t1一直挂起进而无法释放o1锁,而t2需要获取到o1锁后才能继续执行,但苦苦等待,奈何o1被t1拿捏的死死的,从此整个程序就陷入了无尽的等待中----死锁。
作者丨浪舟子
blog.csdn.net/qq_40400960/article/details/112651249
安世半导体致力于为中国汽车半导体保驾护航
特斯拉加州弗里蒙特工厂的Model 3生产线,将停产两周
电吹风发热丝电阻丝点焊机特点的介绍
弹片微针模组能大大提高手机OLED屏幕的测试效率
国外使用超显微镜观察到锂离子在电化学充放电过程
使用stop、suspend方法来中断线程的坏处在哪?
digilent100MSPS USB示波器与逻辑分析仪介绍
2019年智能冰箱产业:解决消费痛点,回归保鲜生活
变压器中,主绝缘、从绝缘指的什么?
针对数字光投影仪而优化的电源电路设计
一款适合于智能家居使用的的智能镜面显示屏
FPGA的数字信号处理:重写FIR逻辑以满足时序要求
端到端自动驾驶到底是什么?
可穿戴创业:以色列的孵化器为何如此给力?
MR-16 LED驱动器和用于脉冲LED冷却器供电的5V辅助
适合中小型企业的智能网关都有哪些
诺基亚确认与蔡司终止合作 不再使用ZEISS镜头
如何用按键控制不同的LED流转模式?
针式打印机的兼容操作系统
云计算的思维转换 无服务器的优势