Java 线程的中断机制(interrupt)

目录

interrupt API

interrupt 使用

Case 1

Case 2

interrupt 对 sleep,join,wait,park 的影响

对Thread.sleep(),Thread.join(),Object.wait()的影响

对LockSupport.park()的影响


         Java没有提供一种安全、直接的方法来停止某个线程,而是提供了一种中断机制。中断机制是一种协作机制,不会直接暴力地终止另一个线程,而需要被中断的线程自己来处理中断信息。被中断的线程即可以选择立即停止、也可以选择稍后再停止、也可以不停止。

interrupt API

  • Thread.interrupt():将某个线程的中断标志位设置成true
  • Thread.isInterrupted() :判断线程的中断标志位是否是true
  • Thread.interrupted() 静态方法 :判断当前线程的中断标志位是否是true,并清除中断标志位设置为false

interrupt 使用

Case 1

 public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (; ; ) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("t1 线程中断,结束");
                } else {
                    System.out.println("t1 线程未中断,继续循环...");
                }
            }
        });
        t1.start();

        Thread.sleep(2000);
        t1.interrupt();
        System.out.println("中断t1线程");
    }
    
}

输出结果:

...
t1 线程未中断,继续循环...
t1 线程未中断,继续循环...
t1 线程未中断,继续循环...
中断t1线程
t1 线程中断,结束
t1 线程中断,结束
t1 线程中断,结束
...

Case 2

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            boolean interrupted = false;
            for (; ; ) {
                if (Thread.interrupted()) {
                    interrupted = true;
                    System.out.println("t1 线程中断并清除中断标志");
                } else {
                    if (interrupted) {
                        System.out.println("t1 线程已中断过并清除中断标志位,继续循环...");
                        break;
                    } else {
                        System.out.println("t1 线程未中断过,继续循环...");
                    }
                }
            }
        });
        t1.start();

        Thread.sleep(1000);
        t1.interrupt();
        System.out.println("中断t1线程");
    }

}

输出结果:

...

t1 线程未中断过,继续循环...
t1 线程未中断过,继续循环...
t1 线程未中断过,继续循环...
中断t1线程
t1 线程中断并清除中断标志
t1 线程已中断过并清除中断标志位,继续循环...

...

interrupt 对 sleep,join,wait,park 的影响

对Thread.sleep(),Thread.join(),Object.wait()的影响

我们知道在写 sleep、join、wait 的时候,都需要显示捕获InterruptedException,当线线程中断时,会立即执行中断异常逻辑,并清除中断标志位。

以sleep为列:

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            System.out.println("t1线程中断 执行sleep中断异常逻辑...");
        }
    });
    t1.start();

    Thread.sleep(3000);
    t1.interrupt();
    System.out.println("中断t1线程");
}

当中断t1线程后会立即输出:"t1线程中断 执行sleep中断异常逻辑..."

对LockSupport.park()的影响

当t1线程LockSupport.park()阻塞时,调用t1.interrutp()会唤醒t1线程,不会清除中断标志位。

我们来看一段ReentrantLock.lock()的源码

    //抢锁逻辑
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();//判断中断标志如果为true,则需要补中断标志
    }

最后会有一个补中断标志的逻辑,why?我们再看一下acquireQueued里的逻辑

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt()) //重点在这里,点进去
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

这里面的逻辑不细看了,重点是parkAndCheckInterrupt方法,点进去

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();//判断中断标志是否为true,并清除中断标志
    }

我们看到parkAndCheckInterrupt()方法中用到了LockSupport.park()方法,即ReetrantLock抢锁失败入队后真正阻塞线程的地方。由于LockSupport.park()被唤醒有两种方式,第一种在解锁逻辑中调用LockSupport.unPark()被唤醒。还有就是当线程被中断时会唤醒线程,此时该方法返回线程中断标志位为true,并清除中断标志位,再走抢锁逻辑,如果抢锁成功了,在执行业务逻辑之前得补一下被清除的中断标志位(给业务某个地方用的)。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值