Java并发编程之ReentrantLock

一、可中断锁

1. 核心方法:lockInterruptibly()

  • 作用:允许线程在等待锁的过程中响应中断请求。
  • 适用场景:需要支持任务取消或中断的同步操作(如用户手动取消长时间等待的任务)。

2. 代码示例

ReentrantLock lock = new ReentrantLock();

Thread thread = new Thread(() -> {
    try {
        lock.lockInterruptibly(); // 可中断获取锁
        try {
            System.out.println("线程获取锁并执行任务");
            Thread.sleep(5000); // 模拟耗时操作
        } finally {
            lock.unlock();
        }
    } catch (InterruptedException e) {
        System.out.println("线程被中断,放弃获取锁");
    }
});

lock.lock(); // 主线程先获取锁
try {
    thread.start();
    Thread.sleep(1000); // 确保子线程开始等待锁
    thread.interrupt(); // 中断子线程
} finally {
    lock.unlock();
}

3. 行为分析

  • 未中断时:线程正常获取锁并执行任务。
  • 中断时:抛出 InterruptedException,线程退出等待队列。

二、锁超时

1. 核心方法:tryLock()

  • 无参方法boolean tryLock()
    立即尝试获取锁,成功返回 true,失败返回 false

  • 带超时方法boolean tryLock(long timeout, TimeUnit unit)
    在指定时间内尝试获取锁,超时后放弃。

2. 代码示例:避免死锁

ReentrantLock lockA = new ReentrantLock();
ReentrantLock lockB = new ReentrantLock();

Thread thread1 = new Thread(() -> {
    try {
        if (lockA.tryLock(1, TimeUnit.SECONDS)) { // 尝试获取lockA
            try {
                if (lockB.tryLock(1, TimeUnit.SECONDS)) { // 尝试获取lockB
                    System.out.println("Thread1完成任务");
                }
            } finally {
                if (lockB.isHeldByCurrentThread()) lockB.unlock();
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        if (lockA.isHeldByCurrentThread()) lockA.unlock();
    }
});

Thread thread2 = new Thread(() -> { /* 类似逻辑,先尝试lockB再lockA */ });
thread1.start();
thread2.start();

3. 应用场景

  • 死锁预防:通过超时放弃锁请求,打破循环等待。
  • 响应性优化:避免线程长时间阻塞影响系统响应速度。

三、条件变量

1. 核心机制

  • 创建条件变量Condition condition = lock.newCondition();
  • 等待条件condition.await();
  • 唤醒线程condition.signal()condition.signalAll()

2. 代码示例:生产者-消费者模型

ReentrantLock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition(); // 非空条件
Condition notFull = lock.newCondition();  // 非满条件
Queue<Integer> queue = new LinkedList<>();
int maxSize = 10;

// 生产者
new Thread(() -> {
    lock.lock();
    try {
        while (queue.size() == maxSize) {
            notFull.await(); // 等待队列非满
        }
        queue.add(1);
        notEmpty.signal(); // 通知消费者
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}).start();

// 消费者
new Thread(() -> {
    lock.lock();
    try {
        while (queue.isEmpty()) {
            notEmpty.await(); // 等待队列非空
        }
        queue.poll();
        notFull.signal(); // 通知生产者
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}).start();

3. 优势对比 wait()/notify()

特性Conditionwait()/notify()
多条件支持✅ 可创建多个条件变量❌ 每个对象仅一个等待队列
精准唤醒signal() 唤醒指定条件队列的线程notify() 随机唤醒

四、关键注意事项

1. 锁释放

  • 必须手动释放lock.unlock() 需放在 finally 块中确保执行。
  • 重入次数匹配:加锁和解锁次数必须一致,否则导致锁无法释放。

2. 中断处理

  • 响应中断lockInterruptibly()await() 需捕获 InterruptedException
  • 恢复中断状态:调用 Thread.currentThread().interrupt() 保留中断标志。
### Java 并发编程 ReentrantLock 使用方法 #### 锁的获取与释放 `ReentrantLock` 提供了多种方式来获取锁,其中最基本的方式是通过 `lock()` 方法。调用此方法会尝试获取锁;如果锁已被其他线程持有,则当前线程会被阻塞,直到能够成功获得锁[^1]。 ```java ReentrantLock lock = new ReentrantLock(); lock.lock(); // 获取锁 try { // 执行临界区代码 } finally { lock.unlock(); // 释放锁 } ``` 为了防止死锁或其他异常情况的发生,在使用 `lock()` 后应当总是确保在 `finally` 块中调用 `unlock()` 来释放锁,即使发生错误也应如此处理以避免资源泄露[^4]。 #### 支持可中断的锁请求 除了基本的锁定操作外,还提供了带有中断特性的版本—`lockInterruptibly()` 。这允许正在等待锁的过程中被外部因素打断,并抛出 `InterruptedException` 异常给调用者知道发生了什么状况[^2]。 ```java ReentrantLock interruptibleLock = new ReentrantLock(); try { interruptibleLock.lockInterruptibly(); // 可能因外界干扰而失败并抛出 InterruptedException try { // 处理受保护的操作... } finally { interruptibleLock.unlock(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复被打断的状态标志位 throw new RuntimeException(e); } ``` #### 非阻塞式的尝试加锁 对于那些不想长时间挂起的情况来说,可以考虑采用 `tryLock()` 或带超时参数的方法来进行非阻塞性质上的尝试性上锁动作。前者会在无法立即取得所有权的情况下立刻返回false值而不做任何停留;后者则是在规定时间内轮询检查是否有可用的机会去占有互斥对象[^3]。 ```java // 不等待直接测试能否拿到锁 if (!myLock.tryLock()) { System.out.println("未能即时得到锁"); } // 设置最大等待时间为5秒 if (myLock.tryLock(5, TimeUnit.SECONDS)) { try { // 成功获得了锁后的逻辑 } finally { myLock.unlock(); } } else { System.out.println("超过设定时间未获授权"); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值