加群联系作者vx:xiaoda0423
仓库地址:webvueblog.github.io/JavaPlusDoc…
webvueblog.github.io/JavaPlusDoc…
📢 联系与资源
-
作者微信:xiaoda0423
-
仓库地址
- JavaPlusDoc(文档) webvueblog.github.io/JavaPlusDoc…
- FastAPI Plus github.com/webVueBlog/…
- 个人博客 1024bat.cn/
锁机制一览
| 分类 | Java 实现/示例 | 特点 | 适用场景 |
|---|---|---|---|
| 悲观锁 | synchronized、ReentrantLock(默认) | 全程加锁,阻塞等待,开销大 | 高冲突写场景 |
| 乐观锁 | 数据库 version 字段+CAS | 无锁操作,提交时校验,冲突回退 | 冲突少、读多写少 |
| 分布式锁 | Redis、ZooKeeper 实现 | 集群环境下的全局互斥 | 分布式系统资源争夺 |
| 可重入锁 | ReentrantLock、synchronized | 同一线程可重复获得,避免自死锁 | 嵌套调用需要二次加锁 |
| 自旋锁 | while(tryLock()){} | 不阻塞线程,循环尝试,占用 CPU | 临界区极短、线程冲突不激烈 |
| 独享锁 | ReentrantLock、写锁 | 单线程占有,互斥执行 | 写操作独占 |
| 共享锁 | ReentrantReadWriteLock 读锁 | 多线程共享,无阻塞读;写时独占 | 读多写少、高并发读 |
| 公平锁 | new ReentrantLock(true) | 按请求顺序分配,防止饥饿 | 对响应时序要求严格 |
| 非公平锁 | 默认 ReentrantLock()、synchronized | 吞吐量高,可能造成线程饥饿 | 性能优先,偶尔可容忍饥饿 |
| 分段锁 | JDK7 ConcurrentHashMap | 将数据分段锁,细化锁粒度 | 大规模并发 Map 操作 |
| 阻塞锁 | lock()、await() | 线程阻塞挂起,唤醒后抢占 | 需等待条件满足、阻塞式协调 |
| 信号量 | Semaphore | 控制多线程对多个资源的并发访问 | 限流、线程池可用许可管理 |
| 条件变量 | Condition | 替代 wait/notify,可精确唤醒指定线程 | 复杂线程通信、分组唤醒 |
| 行级锁 | SQL UPDATE … WHERE | 数据库内部对记录加锁,粒度最细,高性能 | 高并发下库存扣减、状态流转 |
1. 悲观锁(Pessimistic Lock)
-
原理:在读写期间始终加锁,其他线程必须等待。
-
实现:
- Java:
synchronized(重量级锁) - Java:
ReentrantLock默认即悲观锁
- Java:
-
优缺点:
- ✅ 安全、简单
- ❌ 长锁占用导致并发度低,阻塞严重
-
示例:
synchronized(this) { // 处理临界区 }
2. 乐观锁(Optimistic Lock)
-
原理:不加锁,读时取得版本号,写时通过 CAS 验证版本,无冲突则更新。
-
实现:常见于数据库,表中增加
version字段,更新语句:UPDATE table SET col = ?, version = version + 1 WHERE id = ? AND version = ? -
优缺点:
- ✅ 无锁开销,读写几乎不阻塞
- ❌ 冲突时需回滚重试,编程复杂
-
适用:冲突少、读多写少场景,如用户资料更新。
3. 分布式锁(Distributed Lock)
-
原理:借助外部系统(Redis、ZooKeeper、Etcd)维护全局锁。
-
实现:
- Redis:
SET key value NX PX timeout - ZooKeeper:EPHEMERAL + 顺序节点
- Redis:
-
优缺点:
- ✅ 可跨服务/跨语言互斥
- ❌ 需处理单点、性能和超时等问题
-
适用:微服务间资源争抢,如生成唯一订单号。
4. 可重入锁(Reentrant Lock)
-
原理:同一线程可多次获得同一把锁,锁计数器递增/递减。
-
实现:
- Java:
synchronized(内置可重入) - Java:
ReentrantLock
- Java:
-
优点:避免递归调用、嵌套方法中的死锁。
5. 自旋锁(Spin Lock)
-
原理:线程不断轮询尝试获取锁,不进入阻塞状态。
-
实现:
while (!lock.tryLock()) { // 自旋 } try { … } finally { lock.unlock(); } -
优缺点:
- ✅ 不切换线程上下文,低延迟
- ❌ CPU 占用高,适合临界区极短的场景。
6. 读写锁(Read–Write Lock)
-
原理:将锁分为读锁(共享)和写锁(独占)。
-
实现:
ReentrantReadWriteLock -
优缺点:
- ✅ 多线程并发读,高效无阻塞
- ❌ 写锁独占,升级/降级逻辑复杂
-
示例:
ReadWriteLock rw = new ReentrantReadWriteLock(); rw.readLock().lock(); // 读操作 rw.readLock().unlock();
7. 公平锁 vs 非公平锁
| 类型 | 分配策略 | 吞吐量 | 典型实现 |
|---|---|---|---|
| 公平锁 | 按请求顺序(FIFO)分配 | 较低 | new ReentrantLock(true) |
| 非公平锁 | 抢占式,可能插队 | 较高 | 默认 synchronized、ReentrantLock() |
8. 分段锁(Segment Lock)
-
原理:把大数据结构分段,每段独立加锁,降低冲突域。
-
实现:
- JDK7
ConcurrentHashMap用Segment继承ReentrantLock
- JDK7
-
适用:大规模并发 Map 操作。
9. 信号量(Semaphore)
-
原理:内部计数器控制可并发访问资源数。
-
Java 实现:
java.util.concurrent.Semaphore -
示例:
Semaphore sem = new Semaphore(3); sem.acquire(); // 获取许可 try { … } finally { sem.release(); }
10. 条件变量(Condition)
-
原理:替代
wait/notify,多条件队列,可精确唤醒。 -
Java 实现:
Lock.newCondition() -
示例:
Lock lock = new ReentrantLock(); Condition cond = lock.newCondition(); lock.lock(); cond.await(); // 等待 cond.signalAll(); // 唤醒 lock.unlock();
11. 行级锁(Row Lock)
-
原理:数据库引擎对单行记录加锁,粒度最细。
-
示例:
UPDATE inventory SET amount = amount - 1 WHERE id = ? AND amount > 0; -
优点:并发度最高,适合高并发库存扣减、状态流转。
选型建议
- 冲突多、写密集:悲观锁或分布式锁
- 读多写少:乐观锁 + 读写锁
- 分布式环境:Redis/ZooKeeper 分布式锁
- 高并发读写:分段锁 + 读写锁
- 限流场景:信号量