Java 线程中断和LockSupport

Java 线程中断和LockSupport

1.线程中断机制概念

首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止,自己来决定自己的命运。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。

其次,在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的协商机制―---中断,也即中断标识协商机制。

中断只是一种协作协商机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。

若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程请求这条线程中断,此时究竟该做什么需要你自己写代码实现。

每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。

2.中断三大Api解释

2.1 Thread.interrupt()

interrupt() 是一个用于通知线程它应该中断的方法。当线程在执行过程中调用 interrupt() 方法时,它会设置一个标志位(即中断标志),通知线程中断。

  • 作用:通知线程中断,并通过设置中断标志使线程能够响应中断请求。
  • 行为interrupt() 并不会直接停止线程,它只是设置了线程的中断标志。线程可以通过检查中断标志来决定是否终止任务。

代码示例:

java 复制代码
public class InterruptExample extends Thread {
    @Override
    public void run() {
        try {
            // 模拟长时间任务
            for (int i = 0; i < 10; i++) {
                System.out.println("Task running " + i);
                Thread.sleep(1000); // 会抛出 InterruptedException
            }
        } catch (InterruptedException e) {
            System.out.println("Thread was interrupted!");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        InterruptExample thread = new InterruptExample();
        thread.start();
        Thread.sleep(3000); // 主线程休眠 3 秒
        thread.interrupt(); // 中断子线程
    }
}

interrupt() 设置线程的中断标志,并不直接停止线程,线程可以通过判断中断标志来决定是否退出。

2.2 Thread.isInterrupted()

返回中断状态

2.3 Thread.interrupted()

该方法检查当前线程是否已被中断,并且在检查之后会清除中断标志。它是静态方法,所以可以调用它来检测当前线程的中断状态,并清除中断标志。

3.如何停止一个正在运行中的线程

虽然可以直接暴力STOP 但是一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止.

对于线程自己而言,应该不断的去检查状态值,如果识别到应该停止,他应该退出

所以我们可以这样

1.通过volatile 的布尔变量实现

2.通过AtomicBoolean 实现

3.通过线程的中断机制实现

4.哪些阻塞可以被中断,哪些不能

4.1可中断的阻塞

针对线程处于由sleep, wait, joinLockSupport.park等方法调用产生的阻塞状态时,调用interrupt方法,会抛出异常InterruptedException,同时会清除中断标记位,自动改为false。

4.2不可中断的阻塞

  1. java.io包中的同步Socket I/O
  2. java.io包中的同步I/O
  3. Selector的异步I/O
  4. sychronized加的锁

具体来说,当对一个线程,调用interrupt()时:

①如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。所以,interrupt()并不能真正的中断线程,需要被调用的线程自己进行配合才行。

②如果线程处于被阻塞状态(例如处于sleep, wait, join等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。在catch块中应该加上一行代码:Thread.currentThread().interrupt();

为什么要写这个?

这是维持状态。sleep(),wait()方法抛出InterruptException异常后会清除中断标志,即把中断标志设为false。而你又捕获了InterruptException,这时你基本上阻止任何更高级别的方法/线程组注意到中断。这可能会导致问题。通过调用Thread.currentThread().interrupt(),你可以设置线程的中断标志(即把中断标志设为true),因此更高级别的中断处理程序会注意到它并且可以正确处理它。

当前线程的中断标识为true,是不是线程就立刻停止?

实例方法interrupt()仅仅是设置线程的中断状态位为true,不会停止线程。中断只是一种协商机制,修改中断标识位仅此而已,不是立刻stop打断

sleep方法抛出InterruptedException后,中断标识也被清空置为false,我们在catch没有通过调用th.interrupt()方法再次将中断标识置为true,这就导致无限循环了

5.LockSupport是什么

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,其中park()和unpack()而作用分别是阻塞线程和解除阻塞线程

5.1三种让线程等待和唤醒的方法

  • 方式一:使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程
  • 方式二:使用JUC包中的Condition的await()方法让线程等待,使用signal()方法唤醒线程
  • 方式三:LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程
相关推荐
万粉变现经纪人几秒前
如何解决 pip install -r requirements.txt 无效可编辑项 ‘e .‘(-e 拼写错误)问题
开发语言·python·r语言·beautifulsoup·pandas·pip·scipy
say_fall16 分钟前
精通C语言(2.结构体)(内含彩虹)
c语言·开发语言·windows
潇凝子潇16 分钟前
在使用Nacos作为注册中心和配置中心时,如何解决服务发现延迟或配置更新不及时的问题
开发语言·python·服务发现
泉城老铁29 分钟前
springboot实现对接poi 导出excel折线图
java·spring boot·后端
金銀銅鐵1 小时前
[Java] 如何自动生成简单的 Mermaid 类图
java·后端
纵横八荒1 小时前
Java基础加强13-集合框架、Stream流
java·开发语言
稚辉君.MCA_P8_Java1 小时前
kafka解决了什么问题?mmap 和sendfile
java·spring boot·分布式·kafka·kubernetes
乄bluefox1 小时前
保姆级docker部署nacos集群
java·docker·容器
欣然~1 小时前
百度地图收藏地址提取与格式转换工具 说明文档
java·开发语言·dubbo
William_cl2 小时前
C# MVC 修复DataTable时间排序以及中英文系统的时间筛选问题
开发语言·c#·mvc