Thread类方法之二--interrupt

interrupt 方法打断线程

  • case1:打断sleep, wait, join (阻塞)的线程
  • case2:打断运行中的线程

打断阻塞状态中的线程,会抛出一个InterruptedException异常,并且会重置打断标记

  • 介绍一下打断标记

Thread类里有一个isInterrupted方法可以返回当前线程是否被打断,被打断返回true,否则false

public boolean isInterrupted() {
        return isInterrupted(false); // 这里的false指不会重置打断标记
    }

还有一个类似的静态方法interrupted也可以返回当前线程是否被打断,被打断返回true,否则false,但是会重置打断标记为false。

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);  // 这里的true指会重置打断标记
    }
打断阻塞状态的线程
public class Test {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            try {
                Thread.sleep(5000); // wait, join
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        log.debug("打断标记:{}", t1.isInterrupted()); // 1
        t1.interrupt();
        log.debug("打断标记:{}", t1.isInterrupted()); // 2
    }
}

/*Output:
22:29:08.624 c.Test11 [t1] - sleep...
22:29:09.621 c.Test11 [main] - interrupt
22:29:09.621 c.Test11 [main] - 打断标记:false
22:29:09.624 c.Test11 [main] - 打断标记:false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at cn.itcast.test.Test11.lambda$main$0(Test11.java:12)
	at java.lang.Thread.run(Thread.java:748)
*/

上面两个false是意义不同的,第一个代表当前线程正常运行,没有被打断;而第二个false代表线程在sleep, wait, join 中(阻塞状态)被打断,会抛出异常并将打断标记重置为false。

打断正常运行的线程
public class Test {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while(true) {
                System.out.println("isInterrupted状态: " + (Thread.currentThread().isInterrupted()));
            }
        }, "t1");
        t1.start();

        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
    }
}

/*Output:
...
isInterrupted状态: false
isInterrupted状态: false
isInterrupted状态: false
22:43:30.383 c.Test12 [main] - interrupt
isInterrupted状态: true
isInterrupted状态: true
isInterrupted状态: true
...

打断后标记变为true, 但是进程并没有停止,那么这个打断到底有啥用啊?我们怎么让被打断后的进程停下来哪?我们可以借助打断标记,如果打断标记为真,就手动退出进程。

public class Test {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while(true) {
                boolean interrupted = Thread.currentThread().isInterrupted();
                if(interrupted) {
                    log.debug("被打断了, 退出循环");
                    break;
                }
            }
        }, "t1");
        t1.start();

        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
    }
}

/*Output:
22:52:17.742 c.Test12 [main] - interrupt
22:52:17.747 c.Test12 [t1] - 被打断了, 退出循环
*/

interrupt应用:多线程设计模式之两阶段终止

Two Phase Termination :在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。

错误思路
  • 使用线程对象的 stop() 方法停止线程
    • stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁, 其它线程将永远无法获取锁
  • 使用 System.exit(int) 方法停止线程
    • 目的仅是停止一个线程,但这种做法会让整个程序都停止
两阶段终止模式
  • 应用场景:后台监控线程(需要设置停止选项)
  • 思路
    在这里插入图片描述
@Slf4j(topic = "c.TwoPhaseTermination")
public class Test_1 {
    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTermination_1 tpt = new TwoPhaseTermination_1();
        tpt.start();

        Thread.sleep(3500);
        log.debug("停止监控");
        tpt.stop();
    }
}

@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination_1 {
    // 监控线程
    private Thread monitorThread;

    // 启动监控线程
    public void start() {
        monitorThread = new Thread(() -> {
            while (true) {
                Thread current = Thread.currentThread();
                // 是否被打断
                if (current.isInterrupted()) {
                    log.debug("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);          // 睡眠时被打断
                    log.debug("执行监控记录");   // 正常打断
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // 当抛出异常时,重新设置打断标记
                    current.interrupt();
                }
            }
        }, "monitor");
        monitorThread.start();
    }

    // 停止监控线程
    public void stop() {
        monitorThread.interrupt();
    }
}

/*Output:
00:30:54.263 c.TwoPhaseTermination [monitor] - 执行监控记录
00:30:55.263 c.TwoPhaseTermination [monitor] - 执行监控记录
00:30:56.265 c.TwoPhaseTermination [monitor] - 执行监控记录
00:30:56.765 c.TwoPhaseTermination [main] - 停止监控
00:30:56.765 c.TwoPhaseTermination [monitor] - 料理后事
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at cn.itcast.test.TwoPhaseTermination_1.lambda$start$0(Test_1.java:33)
	at java.lang.Thread.run(Thread.java:748)
*/

在睡眠时被打断,抛出异常并优雅的退出线程。正常运行时被打断,优雅的退出线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值