在多线程编程中,锁是保证线程安全的核心工具。本文将详解Java中常见的锁机制及其实际应用场景,帮助开发者选择最合适的锁方案。
一、内置锁:synchronized
原理
通过JVM内置的监视器锁(Monitor)实现,可修饰方法或代码块。
// 修饰方法
public synchronized void add() {
// 线程安全操作
}
// 修饰代码块
public void increment() {
synchronized(this) {
// 线程安全操作
}
}
场景
-
单机简单同步:如计数器、对象状态变更
-
资源竞争低:性能要求不高的场景
二、显式锁:ReentrantLock
特性
-
可重入性
-
支持公平/非公平锁
-
尝试获取锁(tryLock)
-
可中断锁
ReentrantLock lock = new ReentrantLock();
public void performTask() {
lock.lock();
try {
// 临界区操作
} finally {
lock.unlock(); // 必须手动释放
}
}
场景
-
复杂同步逻辑:需要尝试获取锁
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// 获取锁成功
} finally {
lock.unlock();
}
}
-
公平性要求:防止线程饥饿
-
锁分离:配合Condition实现等待通知机制
三、读写锁:ReentrantReadWriteLock
原理
分离读锁(共享)和写锁(独占),提升读多写少场景的性能。
ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void readData() {
rwLock.readLock().lock();
try {
// 读取操作
} finally {
rwLock.readLock().unlock();
}
}
public void writeData() {
rwLock.writeLock().lock();
try {
// 写入操作
} finally {
rwLock.writeLock().unlock();
}
}
场景
-
缓存系统:如热点数据缓存
-
配置中心:频繁读取,偶尔更新配置
四、乐观锁:StampedLock(JDK8+)
特性
-
乐观读锁
-
锁升级机制
StampedLock stampedLock = new StampedLock();
// 乐观读
public double read() {
long stamp = stampedLock.tryOptimisticRead();
// 读取数据...
if (!stampedLock.validate(stamp)) {
stamp = stampedLock.readLock(); // 升级为悲观锁
try {
// 重新读取
} finally {
stampedLock.unlockRead(stamp);
}
}
return data;
}
// 写锁
public void write() {
long stamp = stampedLock.writeLock();
try {
// 写操作
} finally {
stampedLock.unlockWrite(stamp);
}
}
场景
-
高并发读:如股票行情系统
-
数据校验:先快速读取后验证
五、分布式锁
实现方式
-
Redis(RedLock算法)
-
ZooKeeper(临时有序节点)
-
数据库(唯一约束)
// Redis分布式锁示例(Jedis)
public boolean tryLock(String key, String value, int expire) {
return "OK".equals(jedis.set(key, value, "NX", "EX", expire));
}
public void unlock(String key, String value) {
if (value.equals(jedis.get(key))) {
jedis.del(key);
}
}
场景
-
分布式系统:集群服务定时任务
-
资源抢占:如秒杀系统库存扣减
六、锁优化实践
-
减小锁粒度:ConcurrentHashMap分段锁
-
无锁编程:Atomic原子类
-
避免死锁:按顺序获取锁
-
锁分离:读写锁分离
总结对比
锁类型 | 特性 | 适用场景 |
---|---|---|
synchronized | 自动释放,非中断 | 简单同步 |
ReentrantLock | 灵活控制,可中断 | 复杂同步逻辑 |
ReadWriteLock | 读写分离 | 读多写少 |
StampedLock | 乐观读,高性能 | 高并发读 |
分布式锁 | 跨JVM | 分布式系统 |
选择合适的锁能显著提升系统性能。理解各锁的特性及适用场景,是构建高并发系统的关键技能。在实际开发中,建议先用synchronized,当需要更细粒度控制时再考虑显式锁。