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类可以阻塞当前线程以及唤醒指定被阻塞的线程
相关推荐
kyle~18 分钟前
C/C++字面量
java·c语言·c++
纨妙23 分钟前
python打卡day59
开发语言·python
neoooo26 分钟前
别慌,Java只有值传递——一次搞懂“为啥我改了它还不变”!
java·后端·spring
秋难降27 分钟前
Python 知识 “八股”:给有 C 和 Java 基础的你😁😁😁
java·python·c
wuxuanok29 分钟前
Web后端开发-请求响应
java·开发语言·笔记·学习
livemetee37 分钟前
spring-ai 1.0.0 (3)交互增强:Advisor 顾问模块
java
DDDDDouble43 分钟前
<二>Sping-AI alibaba 入门-记忆聊天及持久化
java·人工智能
Sally璐璐1 小时前
IPSAN 共享存储详解:架构、优化与落地实践指南
开发语言·php
像风一样的男人@1 小时前
python --货车装厢问题
开发语言·python
一切顺势而行1 小时前
kafka总结
java