ReentrantLock源码lock和tryLock区别

ReentrantLock的lock方法包含尝试加锁和排队功能,若加锁失败会进入等待队列。而tryLock仅尝试加锁,成功返回true,失败返回false,不涉及排队机制。

在reentrantLock中,提供了一个lock和一个tryLock方法,这两个方法是有区别的,这篇笔记主要记录下具体的区别信息

结论

其实对于这个两个方法,简单来说,tryLock()方法,返回的是一个boolean类型变量,返回true,表示加锁成功,返回false,表示加锁失败,但是这个方法是没有排队的功能的
lock()方法有两个功能:尝试加锁 + 排队;所以,lock方法如果加锁失败,会去排队,我们也可以简单的认为,lock = tryLock + 排队方法

lock()源码

lock在加锁的时候,我们看下源码,以非公平锁为例

/**
 * 非公平锁在加锁的时候,会先尝试加锁,如果加锁失败,就调用acquire();
 * 在acquire()方法中,公平锁和非公平锁的区别是:在state为1的时候,非公平锁不会判断当前是否允许加锁,而是直接cas加锁,如果加锁失败,就去排队,后面的流程,就和公平锁一样了
 */
final void lock() {
	if (compareAndSetState(0, 1))
		setExclusiveOwnerThread(Thread.currentThread());
	else
		acquire(1);
}


public final void acquire(int arg) {
	if (!tryAcquire(arg) &&
		acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
		selfInterrupt();
}

protected final boolean tryAcquire(int acquires) {
	return nonfairTryAcquire(acquires);
}

这里可以看到,有两个方法,一个是tryAcquire方法,一个是acquireQueued方法,这两个方法,分别是尝试加锁方法,和排队方法

tryLock()源

<think>我们被要求介绍ReentrantLock源码使用方法。根据引用内容,ReentrantLockJava中一个重要的锁实现,它提供了比synchronized更灵活的锁操作。我们将从以下几个方面进行介绍: 1. ReentrantLock概述 2. 核心源码解析(包括Sync、NonfairSync、FairSync) 3. 使用方法 4. 与synchronized的对比 5. 总结 注意:由于源码解析可能较长,我们将重点放在关键部分,如加锁解锁过程。 # ReentrantLock源码解析及其使用方法 ## 一、ReentrantLock概述 `ReentrantLock`是`java.util.concurrent.locks`包下的一个可重入互斥锁,实现了`Lock`接口。它提供了与`synchronized`关键字相同的互斥性内存可见性,但增加了可中断的锁获取、超时获取锁、公平锁等高级功能[^1]。 **核心特性**: - **可重入性**:同一个线程可以多次获得同一把锁。 - **公平性选择**:支持公平锁非公平锁(默认非公平)。 - **锁获取的灵活性**:提供了`tryLock()`、`lockInterruptibly()`等方法。 ## 二、源码解析 ### 1. 类结构 ```java public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; // 同步器,继承自AQS abstract static class Sync extends AbstractQueuedSynchronizer { ... } static final class NonfairSync extends Sync { ... } // 非公平锁 static final class FairSync extends Sync { ... } // 公平锁 } ``` - **Sync**:继承自`AbstractQueuedSynchronizer`(AQS),是锁实现的核心。 - **NonfairSync**:非公平锁实现(默认)。 - **FairSync**:公平锁实现。 ### 2. 非公平锁加锁过程(`NonfairSync.lock()`) ```java final void lock() { if (compareAndSetState(0, 1)) // 尝试CAS快速获取锁 setExclusiveOwnerThread(Thread.currentThread()); // 成功则设置当前线程为独占线程 else acquire(1); // 进入AQS的acquire方法 } // AQS的acquire方法 public final void acquire(int arg) { if (!tryAcquire(arg) && // 再次尝试获取锁(非公平体现) acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 加入同步队列并阻塞 selfInterrupt(); } // NonfairSync的tryAcquire实现 protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } // Sync中的nonfairTryAcquire final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 锁未被占用 if (compareAndSetState(0, acquires)) { // CAS尝试获取 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 重入 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } ``` **非公平性体现**:线程在请求锁时,先尝试一次CAS获取(不检查等待队列),失败后再进入AQS的同步队列排队。 ### 3. 公平锁加锁过程(`FairSync.lock()`) ```java final void lock() { acquire(1); // 直接进入AQS的acquire,不会尝试插队 } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 关键区别:检查是否有前驱节点(等待队列中是否有线程在等待) if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 重入 // ... 同非公平锁 } return false; } ``` **公平性体现**:在获取锁时,先检查同步队列中是否有等待的线程(`hasQueuedPredecessors()`),如果有则放弃获取。 ### 4. 解锁过程(`unlock()`) ```java public void unlock() { sync.release(1); // 调用AQS的release } // AQS的release public final boolean release(int arg) { if (tryRelease(arg)) { // 尝试释放锁 Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); // 唤醒后继节点 return true; } return false; } // Sync中的tryRelease protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { // 完全释放 free = true; setExclusiveOwnerThread(null); } setState(c); return free; } ``` **重入计数**:每次释放锁,状态值`state`减1,直到为0才完全释放。 ## 三、使用方法 ### 1. 基本使用模板 ```java ReentrantLock lock = new ReentrantLock(); // 默认非公平锁 // ReentrantLock lock = new ReentrantLock(true); // 公平锁 lock.lock(); // 阻塞获取锁 try { // 临界区代码 } finally { lock.unlock(); // 必须在finally中释放锁 } ``` ### 2. 高级用法 #### (1) 尝试获取锁(`tryLock()`) ```java if (lock.tryLock()) { // 立即返回是否成功 try { /* 操作 */ } finally { lock.unlock(); } } else { // 执行其他操作 } // 超时等待 if (lock.tryLock(1, TimeUnit.SECONDS)) { try { /* 操作 */ } finally { lock.unlock(); } } else { // 超时处理 } ``` #### (2) 可中断获取锁(`lockInterruptibly()`) ```java try { lock.lockInterruptibly(); // 可响应中断 try { /* 操作 */ } finally { lock.unlock(); } } catch (InterruptedException e) { // 中断处理 Thread.currentThread().interrupt(); // 恢复中断状态 } ``` #### (3) 条件变量(`Condition`) ```java Condition condition = lock.newCondition(); // 线程1:等待条件 lock.lock(); try { while (!conditionSatisfied) { condition.await(); // 释放锁并等待 } // 条件满足后执行 } finally { lock.unlock(); } // 线程2:唤醒 lock.lock(); try { conditionSatisfied = true; condition.signal(); // 唤醒一个等待线程 } finally { lock.unlock(); } ``` ## 四、与synchronized对比 | **特性** | **ReentrantLock** | **synchronized** | |-------------------|------------------------------------|---------------------------| | **实现方式** | Java API(AQS) | JVM关键字(monitor) | | **锁释放** | 必须手动`unlock()` | 自动释放 | | **可中断** | 支持(`lockInterruptibly()`) | 不支持 | | **公平性** | 支持(构造参数指定) | 仅非公平 | | **条件变量** | 支持多个`Condition` | 单一等待队列 | | **锁绑定** | 可跨方法释放 | 方法/代码块内 | ## 五、总结 - **优先使用场景**: - 需要高级功能(如可中断、超时、公平锁)时选择`ReentrantLock`。 - 简单同步场景仍可使用`synchronized`(代码简洁且自动释放)。 - **注意事项**: - 必须使用`try-finally`确保锁释放,避免死锁。 - 公平锁会降低吞吐量,除非必要否则使用非公平锁。 > 📖 **设计思想启示**:`ReentrantLock`通过AQS实现,将锁的获取与释放逻辑交给子类实现(模板方法模式),同时面向接口设计(`Lock`)隐藏了实现细节,使锁的使用与实现解耦[^2][^5]。 --- ### 相关问题 1. `ReentrantLock`的公平锁非公平锁在性能上有何差异? 2. 如何通过AQS自定义实现一个锁? 3. `ReentrantLock`与`synchronized`在重入实现上有何异同? 4. 为什么`ReentrantLock`的默认实现是非公平锁?</think># ReentrantLock源码解析与使用指南 ## 一、ReentrantLock核心概述 `ReentrantLock`是Java并发包(`java.util.concurrent.locks`)中的**可重入互斥锁**实现,它提供了比`synchronized`更灵活的锁控制能力。主要特性包括: 1. **可重入性**:同一线程可多次获取同一把锁 2. **公平性选择**:支持公平锁与非公平锁(默认非公平) 3. **锁获取灵活性**:提供`tryLock()`、`lockInterruptibly()`等高级方法 4. **条件变量支持**:可通过`newCondition()`创建多个等待队列 ```java // 基本使用示例 ReentrantLock lock = new ReentrantLock(); lock.lock(); // 获取锁 try { // 临界区代码 } finally { lock.unlock(); // 必须手动释放 } ``` ## 二、核心源码解析 ### 1. 类结构体系 ```mermaid classDiagram class Lock { <<interface>> +lock() +unlock() +tryLock() } class ReentrantLock { -Sync sync +ReentrantLock() +ReentrantLock(boolean fair) } class Sync { <<abstract>> +nonfairTryAcquire() +tryRelease() } class NonfairSync { +lock() +tryAcquire() } class FairSync { +lock() +tryAcquire() } Lock <|.. ReentrantLock ReentrantLock *-- Sync Sync <|-- NonfairSync Sync <|-- FairSync ``` ### 2. 关键组件解析 #### (1) Sync同步器(继承AQS) ```java abstract static class Sync extends AbstractQueuedSynchronizer { // 非公平获取尝试 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 获取锁状态 if (c == 0) { if (compareAndSetState(0, acquires)) { // CAS尝试获取锁 setExclusiveOwnerThread(current); // 设置独占线程 return true; } } // 重入逻辑:当前线程已持有锁 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; // 增加重入计数 setState(nextc); return true; } return false; } // 释放锁实现 protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { // 完全释放 free = true; setExclusiveOwnerThread(null); } setState(c); return free; } } ``` #### (2) 非公平锁实现(NonfairSync) ```java static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1)) // 尝试直接获取锁(插队) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); // 进入AQS队列 } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); // 调用父类非公平获取 } } ``` #### (3) 公平锁实现(FairSync) ```java static final class FairSync extends Sync { final void lock() { acquire(1); // 直接进入队列(不插队) } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 关键区别:检查是否有前驱节点(保证公平性) if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 重入逻辑与非公平锁相同 else if (current == getExclusiveOwnerThread()) { // ... } return false; } } ``` ### 3. AQS同步队列工作原理 ```mermaid graph LR A[线程尝试获取锁] --> B{锁是否空闲?} B -->|是| C[CAS获取锁] B -->|否| D[加入CLH队列尾部] D --> E[进入阻塞状态] C --> F[执行临界区代码] F --> G[释放锁] G --> H[唤醒队列中下一个线程] ``` ## 三、高级使用技巧 ### 1. 锁获取的三种方式 ```java ReentrantLock lock = new ReentrantLock(); // 1. 阻塞获取 lock.lock(); // 2. 可中断获取 try { lock.lockInterruptibly(); // 可响应中断 } catch (InterruptedException e) { // 处理中断 } // 3. 尝试获取 if (lock.tryLock()) { // 立即返回 // 获取成功 } else { // 执行备选方案 } // 带超时尝试 if (lock.tryLock(1, TimeUnit.SECONDS)) { // ... } ``` ### 2. 条件变量(Condition)使用 ```java ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); // 创建条件变量 // 等待线程 lock.lock(); try { while (!conditionSatisfied) { condition.await(); // 释放锁并等待 } // 条件满足后执行 } finally { lock.unlock(); } // 通知线程 lock.lock(); try { conditionSatisfied = true; condition.signalAll(); // 唤醒所有等待线程 } finally { lock.unlock(); } ``` ### 3. 公平锁与非公平锁选择 ```java // 非公平锁(默认,吞吐量高) ReentrantLock unfairLock = new ReentrantLock(); // 公平锁(减少线程饥饿,吞吐量较低) ReentrantLock fairLock = new ReentrantLock(true); ``` ## 四、性能优化与最佳实践 1. **锁释放保证**:必须将`unlock()`放在`finally`块中 ```java lock.lock(); try { // 临界区 } finally { lock.unlock(); // 确保锁释放 } ``` 2. **避免嵌套锁**:防止死锁发生 ```java // 危险示例(易死锁) public void methodA() { lock.lock(); try { methodB(); // 内部再次获取锁 } finally { lock.unlock(); } } public void methodB() { lock.lock(); // 重入安全,但设计不推荐 try { ... } finally { lock.unlock(); } } ``` 3. **锁粒度控制**:跨方法加锁示例 ```java public class ResourceManager { private final ReentrantLock lock = new ReentrantLock(); public void initResource() { lock.lock(); // ...初始化资源 // 注意:不在该方法解锁 } public void releaseResource() { try { /* 使用资源 */ } finally { lock.unlock(); } // 在另一方法释放 } } ``` ## 五、与synchronized对比 | **特性** | **ReentrantLock** | **synchronized** | |-------------------|------------------------------------|---------------------------| | **实现机制** | Java API(基于AQS) | JVM内置(monitor) | | **锁释放** | 必须手动`unlock()` | 自动释放 | | **公平性** | 支持(构造参数指定) | 仅非公平 | | **可中断性** | 支持(`lockInterruptibly()`) | 不支持 | | **条件变量** | 支持多个`Condition` | 单一等待队列 | | **性能** | 高竞争场景更优 | 低竞争场景更优 | ## 六、适用场景 1. **需要高级功能**:锁超时、可中断锁获取 2. **公平性要求**:需要按请求顺序获取锁 3. **跨方法锁控制**:在多个方法中持有释放锁 4. **读写分离需求**:结合`ReentrantReadWriteLock`使用 5. **高竞争环境**:减少线程上下文切换开销 > **设计思想启示**:ReentrantLock通过面向接口设计(实现Lock接口)AQS抽象,**将锁的使用与实现分离**,使开发者无需关注底层同步细节即可安全使用[^2][^5]。这种设计既保证了易用性,又提供了灵活的扩展能力。 --- ### 相关问题 1. ReentrantLock的公平锁与非公平锁在性能上有何差异? 2. 如何通过AQS实现自定义同步器? 3. Condition条件变量与Object.wait()/notify()有何异同? 4. ReentrantLock在死锁检测与恢复方面有何优势? 5. JDK中哪些并发工具基于AQS实现?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值