当前位置: 首页 > backend >正文

ReentrantLock的lockInterruptibly有什么用

文章目录

      • 1. 标准 `lock()` 方法的问题
      • 2. `lockInterruptibly()` 的解决方案
      • 3. `lock()` vs `lockInterruptibly()` 对比
      • 4. 使用场景示例:响应取消操作
      • 总结

ReentrantLock.lockInterruptibly()ReentrantLock 提供的一个非常重要的获取锁的方法,它的核心作用是:在等待获取锁的过程中,允许线程响应中断。

这与标准的 lock() 方法形成了鲜明对比,理解它们的区别是掌握 ReentrantLock 的关键。


1. 标准 lock() 方法的问题

首先,我们来看一下标准的 lock() 方法:

lock.lock();
try {// ... 临界区代码 ...
} finally {lock.unlock();
}

lock() 方法会一直尝试获取锁。如果锁被其他线程持有,当前线程就会进入阻塞状态,并且对中断信号(Thread.interrupt())完全无动于衷。它会一直傻等下去,直到成功获取到锁为止。

这在某些场景下会成为一个问题。比如:

  • 一个任务正在等待一个永远不会被释放的锁(例如,持有锁的线程崩溃了),你希望能够取消这个等待的任务,但它对中断没反应。
  • 发生死锁时,所有相关线程都在使用 lock() 相互等待,它们都无法被中断,导致程序永久卡死。

2. lockInterruptibly() 的解决方案

lockInterruptibly() 方法就是为了解决上述问题而设计的。它的行为是:

  1. 尝试获取锁:和 lock() 一样,如果锁是可用的,它会立即获取锁并返回。
  2. 进入可中断的等待:如果锁不可用,当前线程会进入阻塞等待状态。但与 lock() 不同的是,这个等待状态是可以被中断的。
  3. 响应中断:如果在等待期间,有其他线程调用了 waitingThread.interrupt() 来中断这个正在等待的线程,那么:
    • lockInterruptibly()立即停止等待
    • 它不会继续尝试获取锁,而是会抛出 InterruptedException 异常
    • 同时,线程的中断状态会被清除

3. lock() vs lockInterruptibly() 对比

特性lock()lockInterruptibly()
中断响应不响应中断。会一直等待直到获取锁。响应中断。在等待期间如果被中断,会立即停止并抛出异常。
抛出异常不会因为中断而抛出异常。会抛出 InterruptedException
使用场景适用于不关心线程中断,必须获取到锁才能继续的场景。适用于需要可取消可超时的锁等待操作,以及避免死锁的场景。

4. 使用场景示例:响应取消操作

想象一个场景,一个长时间运行的任务需要获取一个锁,但我们希望用户可以随时取消这个任务。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockInterruptiblyExample {private static final Lock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {// 线程 T1 先获取锁并且长时间持有Thread t1 = new Thread(() -> {lock.lock();try {System.out.println("T1: 获取到锁,并开始长时间工作...");Thread.sleep(10000); // 模拟长时间持有锁} catch (InterruptedException e) {// ...} finally {System.out.println("T1: 工作完成,释放锁。");lock.unlock();}}, "T1");// 线程 T2 尝试获取锁,但使用 lockInterruptibly()Thread t2 = new Thread(() -> {System.out.println("T2: 尝试获取锁...");try {// 使用 lockInterruptibly(),使得等待过程可以被中断lock.lockInterruptibly();try {System.out.println("T2: 终于获取到锁了!");} finally {lock.unlock();}} catch (InterruptedException e) {System.out.println("T2: 在等待锁的过程中被中断了,不再等待!");}}, "T2");t1.start();// 确保 T1 先拿到锁Thread.sleep(100);t2.start();// 让 T2 等待2秒Thread.sleep(2000);// 主线程决定不等了,取消 T2 的任务System.out.println("Main: 决定中断 T2 的等待。");t2.interrupt(); // 中断 T2}
}

输出结果:

T1: 获取到锁,并开始长时间工作...
T2: 尝试获取锁...
Main: 决定中断 T2 的等待。
T2: 在等待锁的过程中被中断了,不再等待!
T1: 工作完成,释放锁。

分析:

  1. T1 获取了锁并持有不放。
  2. T2 调用 lockInterruptibly() 开始等待锁,进入阻塞。
  3. 主线程在2秒后调用 t2.interrupt()
  4. 正在等待的 T2 立刻响应了这个中断,lockInterruptibly() 抛出 InterruptedExceptionT2 进入 catch 块并结束,它放弃了对锁的等待。

如果 T2 使用的是 lock(),那么它会一直等到 T1 在10秒后释放锁,期间对 interrupt() 调用完全不理会。

总结

lockInterruptibly() 提供了一种可取消的、对中断友好的锁获取机制。当你需要编写健壮的、能及时响应取消或关闭信号的并发代码时,它是一个非常重要的工具,尤其是在处理可能长时间阻塞或潜在死锁的场景中。

其实还是lock方法的变种,只不过一个是死等,一个是可以响应中断的等,A死等,B等了半天,完了之后C叫他喂喂喂,别等了,赶紧撤吧,B就哦哦哦,于是B提桶跑路了

http://www.xdnf.cn/news/14184.html

相关文章:

  • 【二叉树】(四)二叉搜索树的基础修改构造及属性求解1
  • Java 小工具 - 节假日判断(包含周末),并提供离线版和在线版
  • 《单光子成像》第三章 预习2025.6.13
  • java集合篇(五) ---- List接口
  • 【技术追踪】用于 CBCT 到 CT 合成的纹理保持扩散模型(MIA-2025)
  • 3GPP协议PDF下载
  • Wireshark安装
  • shader实现发亮的粒子 + 透明度渲染可能出现的坑
  • Python学习(9) ----- Python的Flask
  • 课程笔记gitHub案例数据请求与展示
  • AIGC 基础篇 Python基础 06 函数基础
  • 嵌入式linux GDB使用教程
  • App渠道效果怎么统计和对比,有哪些实用方法和工具?
  • ROS的tf_tree中的节点含义详解
  • QGraphicsView
  • 【GESP真题解析】第 6 集 GESP 四级 2023 年 9 月编程题 1:进制转换
  • 【wvp-pro-gb28181】新建CallIdHeader失败的原因解析记录
  • 自动化KVM虚拟机创建脚本详解:从模板到高效部署的线上实践!
  • 【笔记】在新版本 Windows 系统安装回 Windows Subsystem for Android(WSA)
  • 「从实验室到工程现场:机器学习赋能智能水泥基复合材料研发全流程解析」
  • 表达式的自动类型转换
  • [Latex排版] 解决Something‘s wrong--perhaps a missing \item. 问题
  • 车辆车架号查询接口如何用Python实现调用?
  • 算法学习笔记:3.广度优先搜索 (BFS)——二叉树的层序遍历
  • 109.临时解决401错误
  • 线性三角波连续调频毫米波雷达目标识别
  • 【Vue2+antd 表格一直loading的问题】是赋值原因
  • Java 项目中实现统一的 追踪ID,traceId实现分布式系统追踪
  • 贵州建筑安全员C证理论考试题库
  • CHS和LBA的地址与的磁盘关联