并发编程——如何终止线程
前言
今天简单的讲一讲如何终止线程。
如果对于线程的创建方式不太了解,推荐观看并发编程——认识java里的线程
对于线程状态及其切换不了解的,推荐观看并发编程——Java线程的6种状态及切换
对于线程的启动不了解的,推荐观看并发编程——线程的启动
终止线程
终止线程的方式
1、使用标记变量
我们通过继承Thread来创建一个自定义的线程类,里面live这个属性是用来控制线程是否终止

使用main方法去测试,启动线程,然后延迟20毫秒,然后我们去改变这个live,使其跳出循环,继续往下走,执行完run,达到一个线程自然执行完终止的效果。

下面是执行结果,看到结果如我们预想的那样,跳出循环之后,现成终止。

2、使用stop方法
首先看一下stop的源码,我们发现这个方法使用了@Deprecated注解,表示不推荐使用,是被废除的。
这个方法目前还是能够达到终止线程的目的,但是这个方法是不安全的,或者说是比较暴力的中断执行,导致是代码不能执行完,逻辑不完整,而且会释放所有锁资源,影响原子操作,数据不一致问题。所以如果你不知道当前线程的一些执行情况,占用资源的情况的话,还是不推荐使用。
JDK 文档中还引入用一篇文章来解释了弃用这些方法的原因:《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
为什么弃用stop:
- 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
-
调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
3、使用interrupt方法
跟interrupt在Thread类中相关的有三个方法,分别是interrupt(),interrupted(),isInterrupted()。
下面来分析一下这三个方法的区别,以及用法。
isInterrupted()
通过面向对象思想我们大概就能猜出来,再看到它的返回值是一个boolean类型,那就十之八九能知道这个方法就是获取当前这个中断信号的值是什么。

继续深入点进去发现调用的是一个native本地方法,接收一个是否清除Interrupted标志位的参数,isInterrupted()传递过来的是一个false,说明不会去清除Interrupted标志位。
下面测试结果发现这个方法会在中断线程之后,不会对Interrupted标志位做清除工作,还是true。

interrupted()
首先我们看到这个方法是一个静态方法,interrupted()也调用了isInterrupted(true)方法,不过它传递的参数是true,表示将会清除中断标志位。
下面测试结果发现这个方法会在中断线程之后,会将Interrupted标志位清除,发现清除之后的结果为false。

interrupt()
前面两个是判断是否中断的方法,而interrupt()就是真正触发中断的方法。
中断线程,其实是设置线程的标识位为true。
interrupt()源码:

1、使用isInterrupted()测试代码:

运行结果图:我们发现调用interrupt()之后,标志位变为true,跳出循环,达到一个中断现成的目的。

2、使用interrupted()测试代码:

运行结果图:我们发现调用interrupt()之后,标志位变为true,第二次进入循环,发现不符合,跳出循环,达到一个中断现成的目的。但是使用interrupted()会清除标志位,所以会发现最后一次打印的和之前不一样了,变为false。

这三个方法要搞清楚,这块可能会在面试的时候会问你这三个方法的区别。
感谢诸君的观看,文中如有纰漏,欢迎在评论区来交流。如果这篇文章帮助到了你,欢迎点赞👍关注。