并发编程知识总结
悲观锁与乐观锁
-
悲观锁
-
假设最坏情况,每次修改共享资源时都会加锁,阻塞其他线程访问,直到锁被释放。
- 典型实现:
synchronized、ReentrantLock
- 典型实现:
-
缺点:
-
线程竞争激烈时,频繁的线程唤醒和阻塞会导致 上下文切换开销大。
-
可能引发 死锁。
- 适用场景:写多、竞争激烈的场景,锁的开销较为固定。
-
乐观锁
-
假设最好的情况,不加锁,仅在提交时检查资源是否被修改。
- 实现方式:
-
版本号法:数据库表中增加
version字段,修改前检查version是否匹配。 -
CAS(比较并交换):涉及三个操作数
(内存值、预期值、新值),如果预期值 == 内存值,则修改成功。 -
CAS的底层:
-
Java层面:
Unsafe类调用本地方法实现。 -
操作系统层面:基于 CPU的原子指令,利用 缓存一致性协议 保证原子操作。
-
缺点:
-
并发修改冲突时,失败重试消耗 CPU 资源大。
- ABA 问题(变量值回到了原值但实际经历了多次变化)。
-
适用场景:读多写少、竞争较少的情况。
2024年3月25日大约 4 分钟