中断锁

本文深入探讨了四种多线程执行策略:有状态执行、同步执行、尝试等待执行及可中断执行,详细解析每种策略的应用场景和优劣,如防止资源冲突、避免死锁及响应中断操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考
https://blog.youkuaiyun.com/antony9118/article/details/52664125
https://www.jianshu.com/p/8db9a5c1ce66
多线程调试
https://blog.youkuaiyun.com/nextyu/article/details/79039566

  1. 场景

场景1:如果发现该操作已经在执行中则不再执行(有状态执行)
a、用在定时任务时,如果任务执行时间可能超过下次计划执行时间,确保该有状态任务只有一个正在执行,忽略重复触发。
b、用在界面交互时点击执行较长时间请求操作时,防止多次点击导致后台重复执行(忽略重复触发)。
以上两种情况多用于进行非重要任务防止重复执行,(如:清除无用临时文件,检查某些资源的可用性,数据备份操作等);

场景2:如果发现该操作已经在执行,等待一个一个执行(同步执行,类似synchronized)
这种比较常见大家也都在用,主要是防止资源使用冲突,保证同一时间内只有一个操作可以使用该资源。
但与synchronized的明显区别是性能优势(伴随jvm的优化这个差距在减小)。同时Lock有更灵活的锁定方式,公平锁与不公平锁,而synchronized永远是公平的。
这种情况主要用于对资源的争抢(如:文件操作,同步消息发送,有状态的操作等)
ReentrantLock默认情况下为不公平锁
不公平锁与公平锁的区别:
公平情况下,操作会排一个队按顺序执行,来保证执行顺序。(会消耗更多的时间来排队)
不公平情况下,是无序状态允许插队,jvm会自动计算如何处理更快速来调度插队。(如果不关心顺序,这个速度会更快)

场景3:如果发现该操作已经在执行,则尝试等待一段时间,等待超时则不执行(尝试等待执行)
这种其实属于场景2的改进,等待获得锁的操作有一个时间的限制,如果超时则放弃执行。
用来防止由于资源处理不当长时间占用导致死锁情况(大家都在等待资源,导致线程队列溢出)。

场景4:如果发现该操作已经在执行,等待执行。这时可中断正在进行的操作立刻释放锁继续下一操作
synchronized与Lock在默认情况下是不会响应中断(interrupt)操作,会继续执行完。lockInterruptibly()提供了可中断锁来解决此问题。(场景2的另一种改进,没有超时,只能等待中断或执行完毕)
这种情况主要用于取消某些操作对资源的占用。如:(取消正在同步运行的操作,来防止不正常操作长时间占用造成的阻塞)

 package com.compaas.Controller;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: Test
 * @Author: wangben
 * @Description: ${description}
 * @Date: 2019/8/1 0001 9:28
 */
public class Test extends Thread{
    public static ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        Controller timeLock = new Controller();
        timeLock.fun();
    }
    public static void main(String[] args) {
        Test timeLock = new Test();
        Thread t1 = new Thread(timeLock);
        Thread t2 = new Thread(timeLock);
        Thread t3 = new Thread(timeLock);
        t1.start();
        t2.start();
        t3.start();
    }
}



class Controller {
    public static ReentrantLock lock = new ReentrantLock();
    public void fun() {//此处打断点,idea进行多线程debug调试
        try {
            //tryLock()方法有两个参数,第一个是等待时长,第二个是计时单位,
            // 如果超过给定时间还没有得到锁就会返回false,如果拿到锁就会返回true
            // lock.tryLock()也可以用不传递人和参数,代表如果锁没有被其他线程占用就会返回true,反之返回false.
            if (lock.tryLock(1, TimeUnit.SECONDS)){
                System.out.println(Thread.currentThread().getName()+"执行业务方法时长2秒");
            }else {
                System.out.println(Thread.currentThread().getName()+"获取锁失败");
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            if (lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }
}

<think>嗯,用户想了解Java中ReentrantLock的中断响应机制和使用方法,以及示例代码。我需要先回顾一下ReentrantLock的相关知识,特别是中断机制的部分。根据用户提供的引用内容,引用[2]和[3]提到了ReentrantLock的可中断锁特性。记得ReentrantLock的lockInterruptibly方法允许线程在等待锁的过程中响应中断。 首先,应该解释什么是中断响应机制。就是当线程在等待获取锁时,如果被其他线程调用了interrupt()方法,它可以立即抛出InterruptedException并停止等待,这样可以避免死锁或者长时间阻塞的情况。这一点和synchronized不同,synchronized在等待锁时无法被中断。 接下来,需要给出具体的使用方法。用户可能需要一个示例代码来展示如何在实际中使用lockInterruptibly方法。根据引用中的例子,比如用户提供的FactorialCalculator类用了ReentrantLock的普通lock方法,但递归调用时没问题,因为可重入。但中断机制需要不同的方法。 然后,要考虑示例的结构。可能需要两个线程,一个获取锁后长时间持有,另一个尝试获取锁并等待,此时中断第二个线程。代码中需要处理InterruptedException,并且在finally块中释放锁。注意要正确使用tryLock或者lockInterruptibly的区别,这里用户问的是中断响应,所以应该用lockInterruptibly。 另外,要强调使用lockInterruptibly时必须将获取锁的代码放在try块外,因为如果在获取锁之前就抛出异常,那么不需要释放锁。否则,如果在try块内获取锁,可能会导致在没有获得锁的情况下执行unlock,从而抛出IllegalMonitorStateException。 还要提到与普通lock方法的区别,普通lock方法不响应中断,即使线程被中断,也会一直等待。而lockInterruptibly方法允许线程在等待时响应中断。 最后,总结应用场景,比如需要避免死锁或控制线程执行顺序时使用中断机制。可能还需要注意事项,比如正确释放锁,异常处理等。 检查是否所有引用的内容都正确应用了。引用[2]和[3]提到了可中断锁,所以需要正确标注引用。例如,在解释可中断锁的部分添加引用标记。 现在,组织回答的结构,先概述中断响应机制,然后分步骤说明使用方法,给出示例代码,并解释代码,最后应用场景和注意事项。确保各部分清晰,符合用户要求的系统级指令,比如数学公式用$...$,但这里可能用不上,但代码块需要用正确的格式。</think>### Java ReentrantLock 中断响应机制详解 #### 一、中断响应机制概述 ReentrantLock 的**可中断锁特性**允许线程在等待获取锁时响应中断请求。当线程调用`lockInterruptibly()`方法进入阻塞状态后,若被其他线程调用`interrupt()`方法中断,则会立即抛出`InterruptedException`并终止等待[^2][^3]。这一机制解决了`synchronized`关键字无法中断阻塞线程的问题。 #### 二、使用方法与示例代码 ##### 1. 核心方法 - `lockInterruptibly()`: 可中断方式获取锁,若线程被中断则抛出异常 - `isHeldByCurrentThread()`: 判断当前线程是否持有锁 ##### 2. 代码示例 ```java import java.util.concurrent.locks.ReentrantLock; public class InterruptibleLockDemo { private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { Thread blockingThread = new Thread(() -> { lock.lock(); try { System.out.println("主线程已获取锁,将长期持有"); Thread.sleep(5000); // 模拟长时间操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }); Thread interruptThread = new Thread(() -> { try { System.out.println("子线程尝试获取锁"); lock.lockInterruptibly(); // 可中断方式获取锁 try { System.out.println("子线程成功获取锁"); } finally { lock.unlock(); } } catch (InterruptedException e) { System.out.println("子线程被中断,放弃获取锁"); } }); blockingThread.start(); Thread.sleep(100); // 确保主线程先获取锁 interruptThread.start(); Thread.sleep(1000); // 等待子线程进入阻塞状态 interruptThread.interrupt(); // 中断子线程 } } ``` ##### 3. 输出结果 ``` 主线程已获取锁,将长期持有 子线程尝试获取锁 子线程被中断,放弃获取锁 ``` #### 三、关键点解析 1. **中断触发条件** 线程必须在调用`lockInterruptibly()`后且未获得锁的**阻塞状态**下被中断才会响应 2. **与普通lock()的区别** 普通`lock()`方法会无视中断请求持续等待,而`lockInterruptibly()`允许优雅退出 3. **异常处理要点** 必须将`lockInterruptibly()`调用放在`try`块外部,避免未持有锁时调用`unlock()` #### 四、应用场景 1. 防止死锁:通过中断机制主动终止卡死的线程 2. 响应式系统:快速响应外部终止请求 3. 超时控制:配合`tryLock(time, unit)`实现复杂超时策略 #### 五、注意事项 1. 中断信号是**建议性**的,具体处理逻辑需开发者实现 2. 必须确保在`finally`块中释放锁 3. 不要混淆线程中断与锁状态判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值