重入锁ReentrantLock、死锁和中断响应

本文介绍Java中ReentrantLock的用法及其与synchronized关键字的区别,通过实例演示如何避免死锁,并讨论ReentrantLock提供的高级特性如中断响应和限时等待。

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

import java.util.concurrent.locks.ReentrantLock;

public class IntLock implements Runnable{
	//重入锁ReentrantLock
	public static ReentrantLock lock1 = new ReentrantLock();
	public static ReentrantLock lock2 = new ReentrantLock();

	int lock;
	public IntLock(int lock){
		this.lock = lock;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			if(lock==1){
				lock1.lockInterruptibly();
				Thread.sleep(500);
				lock2.lockInterruptibly();
			}else{
				lock2.lockInterruptibly();
				Thread.sleep(500);
				lock1.lockInterruptibly();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			if(lock1.isHeldByCurrentThread()){
				lock1.unlock();//释放锁
			}
			if(lock2.isHeldByCurrentThread()){
				lock2.unlock();
			}
			System.out.println(Thread.currentThread().getId()+":线程退出");
		}
		
	}
	public static void main(String[] args) throws InterruptedException {
		IntLock r1 = new IntLock(1);
		IntLock r2 = new IntLock(2);
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);
		t1.start();
		t2.start();
		Thread.sleep(1000);
		//t2线程被中断,放弃锁申请,释放已获得的lock2,这个操作使得t1线程顺利获得lock2继续执行下去;
		//若没有此段代码,t2线程没有中断,那么会出现t1获取lock1,请求lock2,而t2获取lock2,请求lock1的相互等待死锁情况
		t2.interrupt();
	}

}

注释t2.interrupt();之后会陷入死锁状态,会看到控制台没有任何输出,程序一直运行,两个线程都在等待获取对方资源

ReenTrantLock,同一个线程每进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。和synchronized差别不大。在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized。

ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。

此外还能通过lock.tryLock(5,TimeUnit.SECONDS)来设置锁申请等待限时,此例就是限时等待5秒获取锁

ReenTrantLock还能进行公平锁设置他有如下构造函数

public ReentrantLock(boolean fair)

当fair为true时,锁是公平的,公平锁一大特点就是不会产生饥饿现象。所谓的公平锁就是先等待的线程先获得锁。但公平锁性能相对低下,默认情况锁是非公平的。

<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. 不要混淆线程中断与锁状态判断
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值