6.9 KiB
6.9 KiB
ReentrantLock 是 Java 并发包中提供的可重入锁,比 synchronized 更灵活。以下是其常见用法:
1. 基础锁使用
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. 尝试获取锁(非阻塞)
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. 带超时的尝试获取锁
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. 可中断的锁获取
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. 公平锁与非公平锁
public class FairLockExample {
// 创建公平锁(按申请顺序获取锁)
private final ReentrantLock fairLock = new ReentrantLock(true);
// 创建非公平锁(默认,性能更高)
private final ReentrantLock unfairLock = new ReentrantLock();
}
6. 条件变量(Condition)
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. 锁的查询方法
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. 综合示例:线程安全的队列
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 对比
public class Comparison {
// synchronized 方式
public synchronized void syncMethod() {
// 临界区代码
}
// ReentrantLock 方式
private final ReentrantLock lock = new ReentrantLock();
public void lockMethod() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
}
}
最佳实践
- 始终在 finally 块中释放锁,防止异常导致锁无法释放
- 不要嵌套过多 tryLock,避免代码复杂度增加
- 公平锁适用于等待时间差异大的场景,但性能较低
- 考虑使用 tryLock 避免死锁
- 合理使用 Condition 替代 Object 的 wait/notify
选择建议
- 简单同步场景:优先使用
synchronized - 需要高级功能(超时、可中断、公平锁):使用
ReentrantLock - 需要多个等待条件:使用
Condition - 性能敏感场景:测试后选择(通常
synchronized性能更好)