如何优雅的停止一个线程?( 二 )

这里有个思考: 当处于 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");我们执行修改后的代码 , 发现如果 sleepwait等可以让线程进入阻塞的方法使线程休眠了 , 而处于休眠中的线程被中断 , 那么线程是可以感受到中断信号的 , 并且会抛出一个 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` 时是存在问题的 , 这也是需要注意的!
volatile 修饰标记位不适用的场景