Java Lock接口
Java Lock接口是Java并发编程中比`synchronized`关键字更灵活的线程同步机制,属于`java.util.concurrent.locks`包的核心组件。它提供了更细粒度的锁控制,支持公平锁、非阻塞尝试锁、可中断锁等高级特性。
概述[编辑 | 编辑源代码]
Lock接口定义了以下核心方法:
- `lock()` - 获取锁(阻塞直到成功)
- `unlock()` - 释放锁
- `tryLock()` - 非阻塞尝试获取锁
- `lockInterruptibly()` - 可中断地获取锁
与`synchronized`相比,Lock接口的主要优势包括:
- 可定时的锁等待(`tryLock(long time, TimeUnit unit)`)
- 公平锁与非公平锁的选择
- 多个条件变量(`Condition`)支持
- 更清晰的代码结构
基础用法[编辑 | 编辑源代码]
以下是最简单的Lock使用示例:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final Lock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock(); // 获取锁
try {
count++;
} finally {
lock.unlock(); // 确保锁被释放
}
}
}
关键点说明: 1. 使用`ReentrantLock`作为Lock接口的实现类 2. `unlock()`必须放在`finally`块中确保释放 3. 锁的获取和释放必须成对出现
高级特性[编辑 | 编辑源代码]
1. 尝试获取锁[编辑 | 编辑源代码]
public boolean transferMoney(Account from, Account to, int amount) {
// 尝试获取两个账户的锁
if (from.getLock().tryLock()) {
try {
if (to.getLock().tryLock()) {
try {
// 执行转账逻辑
return true;
} finally {
to.getLock().unlock();
}
}
} finally {
from.getLock().unlock();
}
}
return false;
}
2. 公平锁[编辑 | 编辑源代码]
创建公平锁:
Lock fairLock = new ReentrantLock(true); // true表示公平锁
3. 条件变量[编辑 | 编辑源代码]
Lock可以关联多个`Condition`对象,实现精细的线程通信:
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await(); // 等待"不满"条件
// 放入元素
notEmpty.signal(); // 通知"不空"条件
} finally {
lock.unlock();
}
}
}
性能考量[编辑 | 编辑源代码]
Lock与synchronized的性能对比:
场景 | synchronized | ReentrantLock |
---|---|---|
20 | 25 | ||
120 | 65 | ||
1500 | 300 |
结论:在高竞争环境下,Lock表现更好;低竞争时synchronized有JVM优化优势。
实际应用案例[编辑 | 编辑源代码]
数据库连接池实现:
public class ConnectionPool {
private final Lock lock = new ReentrantLock();
private final Condition available = lock.newCondition();
private final Set<Connection> pool = new HashSet<>();
public Connection getConnection() throws InterruptedException {
lock.lock();
try {
while (pool.isEmpty()) {
available.await();
}
return pool.iterator().next();
} finally {
lock.unlock();
}
}
public void releaseConnection(Connection conn) {
lock.lock();
try {
pool.add(conn);
available.signal();
} finally {
lock.unlock();
}
}
}
最佳实践[编辑 | 编辑源代码]
1. 总是使用`try-finally`确保锁释放 2. 避免在持有锁时调用外部方法(防止死锁) 3. 锁范围应尽可能小 4. 考虑使用`tryLock`避免死锁 5. 对读多写少的场景考虑`ReadWriteLock`
常见问题[编辑 | 编辑源代码]
Q: Lock和synchronized如何选择? A: 需要高级功能(如超时、公平性)时用Lock;简单场景用synchronized更简洁。
Q: 为什么Lock比synchronized快? A: 主要因为Lock在Java层面实现,而synchronized涉及JVM内部操作,但现代JVM对synchronized优化很多。
Q: Lock会导致内存泄漏吗? A: 不会直接导致,但忘记调用`unlock()`会导致线程永久阻塞。
数学原理[编辑 | 编辑源代码]
锁的公平性可以用排队论模型表示。设:
其中:
- :系统利用率
- :平均服务时间
公平锁保证对所有线程一致。