如何优雅的停止一个线程?( 二 )
这里有个思考: 当处于 sleep
时 , 线程能否感受到中断信号?
- 对于这一特殊情况 , 我们可以将上述代码稍微修改即可进行验证 , 我们将线程1的代码中加入
sleep
同时让睡眠时间加长 , 让正好线程2通知时线程1还处于睡眠状态 , 此时观察是否能感受到中断信号
//创建 interrupt-1 线程Thread thread = new Thread(() -> {while (true) {//判断当前线程是否中断 ,if (Thread.currentThread().isInterrupted()) {System.out.println("线程1 接收到中断信息 , 中断线程...中断标记:" + Thread.currentThread().isInterrupted());Thread.interrupted(); // //对线程进行复位 , 由 true 变成 falseSystem.out.println("经过 Thread.interrupted() 复位后 , 中断标记:" + Thread.currentThread().isInterrupted());//再次判断是否中断 , 如果是则退出线程if (Thread.currentThread().isInterrupted()) {break;}break;}System.out.println(Thread.currentThread().getName() + "线程正在执行...");try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}}, "interrupt-1");
我们执行修改后的代码 , 发现如果sleep
、wait
等可以让线程进入阻塞的方法使线程休眠了 , 而处于休眠中的线程被中断 , 那么线程是可以感受到中断信号的 , 并且会抛出一个InterruptedException
异常 , 同时清除中断信号 , 将中断标记位设置成false
。 这样一来就不用担心长时间休眠中线程感受不到中断了 , 因为即便线程还在休眠 , 仍然能够响应中断通知 , 并抛出异常 。
interrupt
的方式来实现 , 关于他的详细文章看之前文章即可 , 如 InterruptedException
时 , 再次中断设置 , 让程序能后续继续进行终止操作 。 不过对于 interrupt
实现线程的终止在实际开发中发现使用的并不是很多 , 很多都可能喜欢另一种方式 , 通过标记位 。用 volatile 标记位的停止方法
- 关于
volatile
作为标记位的核心就是他的可见性特性 , 我们通过一个简单代码来看:
- @ulr: i-code.online
- @author: zhoucx
- @time: 2020/9/25 14:45
- /public class MarkThreadTest {
//定义标记为 使用 volatile 修饰 private static volatile boolean mark = false;
@Test public void markTest(){
new Thread(() -> {//判断标记位来确定是否继续进行while (!mark){try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程执行内容中...");}}).start();System.out.println("这是主线程走起...");try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//10秒后将标记为设置 true 对线程可见 。 用volatile 修饰mark = true;System.out.println("标记位修改为:"+mark);
}}
上面代码也是我们之前文中的 , 这里不再阐述 , 就是一个设置标记 , 让线程可见进而终止程序 , 这里我们需要讨论的是 , 使用 `volatile` 是真的都是没问题的 , 上述场景是没问题 , 但是在一些特殊场景使用 `volatile` 时是存在问题的 , 这也是需要注意的!