一、Java锁的核心分类
Java锁机制主要分为两类:隐式锁(synchronized) 和 显式锁(Lock接口)。
二、synchronized的底层原理
2.1 对象头与锁状态
每个Java对象头包含Mark Word,存储哈希码、GC年龄、锁状态等信息。锁升级过程如下:
- 偏向锁:首次获取锁时标记线程ID,减少无竞争时的开销。
- 轻量级锁:通过CAS竞争锁标志位,避免线程阻塞。
- 重量级锁:依赖操作系统Mutex实现,线程竞争失败时进入阻塞状态
步代码的字节码实现
- 同步方法:通过
ACC_SYNCHRONIZED
标志标识,JVM隐式加锁。
2.3 最佳实践
- 缩小锁范围:仅同步必要代码块,减少锁竞争。
三、显式锁:ReentrantLock与高级特性
3.1 核心功能
- 可重入性:同一线程多次获取锁,通过计数器实现(类似synchronized)。
- 条件变量:通过
Condition
实现线程间的精确唤醒(如生产者-消费者模型)
3.2 代码示例
Java
private final ReentrantLock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); // 必须手动释放 } }
3.3 与synchronized对比
特性 | synchronized | ReentrantLock |
---|---|---|
锁获取方式 | 自动释放 | 需手动调用unlock() |
公平性支持 | 不支持 | 支持 |
可中断/超时 | 不支持 | 支持 |
性能 | 优化后接近 | 高竞争场景更优 |
四、分布式锁与高并发实践
4.1 Redis分布式锁
- 基础实现:通过
SETNX
命令和超时机制实现。 - Redisson优化:
- 看门狗机制:自动续期锁,防止业务未完成锁过期。
4.2 集群环境下的锁挑战
- 主从一致性:RedLock算法需在多数节点获取锁。
五、锁的常见问题与解决方案
- 死锁:按固定顺序获取锁,或使用
tryLock
超时机制。
六、总结与场景选择
- 单机低竞争:优先使用
synchronized
,简化代码。 - 高灵活需求:选择
ReentrantLock
或ReadWriteLock
。
参考资料: