258 lines
6.9 KiB
Markdown
258 lines
6.9 KiB
Markdown
`ReentrantLock` 是 Java 并发包中提供的可重入锁,比 `synchronized` 更灵活。以下是其常见用法:
|
||
|
||
## 1. 基础锁使用
|
||
|
||
```java
|
||
import java.util.concurrent.locks.ReentrantLock;
|
||
|
||
public class BasicUsage {
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
private int count = 0;
|
||
|
||
public void increment() {
|
||
lock.lock(); // 获取锁
|
||
try {
|
||
count++;
|
||
System.out.println("Count: " + count);
|
||
} finally {
|
||
lock.unlock(); // 必须放在 finally 中确保释放锁
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 2. 尝试获取锁(非阻塞)
|
||
|
||
```java
|
||
public class TryLockExample {
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
|
||
public void tryLockMethod() {
|
||
if (lock.tryLock()) { // 尝试获取锁,立即返回结果
|
||
try {
|
||
// 获取锁成功,执行临界区代码
|
||
System.out.println("获取锁成功");
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
} else {
|
||
// 获取锁失败,执行其他逻辑
|
||
System.out.println("获取锁失败,执行其他操作");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 3. 带超时的尝试获取锁
|
||
|
||
```java
|
||
import java.util.concurrent.TimeUnit;
|
||
|
||
public class TimeoutLockExample {
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
|
||
public void timeoutLockMethod() throws InterruptedException {
|
||
// 尝试在指定时间内获取锁
|
||
if (lock.tryLock(1, TimeUnit.SECONDS)) {
|
||
try {
|
||
System.out.println("在1秒内获取到锁");
|
||
Thread.sleep(2000); // 模拟业务操作
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
} else {
|
||
System.out.println("获取锁超时");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 4. 可中断的锁获取
|
||
|
||
```java
|
||
public class InterruptibleLockExample {
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
|
||
public void interruptibleMethod() throws InterruptedException {
|
||
lock.lockInterruptibly(); // 可响应中断的锁获取
|
||
try {
|
||
// 长时间操作
|
||
while (true) {
|
||
// 模拟长时间任务
|
||
if (Thread.currentThread().isInterrupted()) {
|
||
break;
|
||
}
|
||
}
|
||
} finally {
|
||
if (lock.isHeldByCurrentThread()) {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 5. 公平锁与非公平锁
|
||
|
||
```java
|
||
public class FairLockExample {
|
||
// 创建公平锁(按申请顺序获取锁)
|
||
private final ReentrantLock fairLock = new ReentrantLock(true);
|
||
|
||
// 创建非公平锁(默认,性能更高)
|
||
private final ReentrantLock unfairLock = new ReentrantLock();
|
||
}
|
||
```
|
||
|
||
## 6. 条件变量(Condition)
|
||
|
||
```java
|
||
import java.util.concurrent.locks.Condition;
|
||
import java.util.concurrent.locks.ReentrantLock;
|
||
|
||
public class ConditionExample {
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
private final Condition condition = lock.newCondition();
|
||
private boolean conditionMet = false;
|
||
|
||
public void awaitCondition() throws InterruptedException {
|
||
lock.lock();
|
||
try {
|
||
while (!conditionMet) {
|
||
condition.await(); // 释放锁并等待
|
||
}
|
||
// 条件满足,执行后续操作
|
||
System.out.println("条件满足,继续执行");
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
|
||
public void signalCondition() {
|
||
lock.lock();
|
||
try {
|
||
conditionMet = true;
|
||
condition.signalAll(); // 唤醒所有等待线程
|
||
// 或使用 condition.signal() 唤醒一个线程
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 7. 锁的查询方法
|
||
|
||
```java
|
||
public class LockStatusExample {
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
|
||
public void checkLockStatus() {
|
||
System.out.println("是否被当前线程持有: " + lock.isHeldByCurrentThread());
|
||
System.out.println("是否被锁定: " + lock.isLocked());
|
||
System.out.println("等待队列长度: " + lock.getQueueLength());
|
||
System.out.println("当前线程持有锁的次数: " + lock.getHoldCount());
|
||
|
||
// 获取锁信息
|
||
if (lock.isLocked()) {
|
||
System.out.println("持有锁的线程: " +
|
||
(lock.getOwner() != null ? lock.getOwner().getName() : "null"));
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 8. 综合示例:线程安全的队列
|
||
|
||
```java
|
||
import java.util.LinkedList;
|
||
import java.util.Queue;
|
||
import java.util.concurrent.locks.Condition;
|
||
import java.util.concurrent.locks.ReentrantLock;
|
||
|
||
public class BlockingQueue<T> {
|
||
private final Queue<T> queue = new LinkedList<>();
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
private final Condition notEmpty = lock.newCondition();
|
||
private final Condition notFull = lock.newCondition();
|
||
private final int capacity;
|
||
|
||
public BlockingQueue(int capacity) {
|
||
this.capacity = capacity;
|
||
}
|
||
|
||
public void put(T item) throws InterruptedException {
|
||
lock.lock();
|
||
try {
|
||
while (queue.size() == capacity) {
|
||
notFull.await(); // 队列满,等待
|
||
}
|
||
queue.offer(item);
|
||
notEmpty.signal(); // 唤醒等待获取的线程
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
|
||
public T take() throws InterruptedException {
|
||
lock.lock();
|
||
try {
|
||
while (queue.isEmpty()) {
|
||
notEmpty.await(); // 队列空,等待
|
||
}
|
||
T item = queue.poll();
|
||
notFull.signal(); // 唤醒等待放入的线程
|
||
return item;
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
|
||
public int size() {
|
||
lock.lock();
|
||
try {
|
||
return queue.size();
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 9. 与 synchronized 对比
|
||
|
||
```java
|
||
public class Comparison {
|
||
// synchronized 方式
|
||
public synchronized void syncMethod() {
|
||
// 临界区代码
|
||
}
|
||
|
||
// ReentrantLock 方式
|
||
private final ReentrantLock lock = new ReentrantLock();
|
||
|
||
public void lockMethod() {
|
||
lock.lock();
|
||
try {
|
||
// 临界区代码
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
1. **始终在 finally 块中释放锁**,防止异常导致锁无法释放
|
||
2. **不要嵌套过多 tryLock**,避免代码复杂度增加
|
||
3. **公平锁适用于等待时间差异大的场景**,但性能较低
|
||
4. **考虑使用 tryLock 避免死锁**
|
||
5. **合理使用 Condition 替代 Object 的 wait/notify**
|
||
|
||
## 选择建议
|
||
|
||
- 简单同步场景:优先使用 `synchronized`
|
||
- 需要高级功能(超时、可中断、公平锁):使用 `ReentrantLock`
|
||
- 需要多个等待条件:使用 `Condition`
|
||
- 性能敏感场景:测试后选择(通常 `synchronized` 性能更好) |