栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 线程的中断机制(interrupt)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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,并清除中断标志位,再走抢锁逻辑,如果抢锁成功了,在执行业务逻辑之前得补一下被清除的中断标志位(给业务某个地方用的)。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1013096.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号