乐观锁和悲观锁
本文最后更新于 2025年5月20日 14:36
乐观锁
乐观锁认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源是否被其它线程修改了。乐观锁可以通过版本号机制和 CAS 算法实现。
CAS
- V:要更新的变量值(Var)
- E:预期值(Expected)
- N:拟写入的新值(New)
当且仅当 V 的值等于 E 时,CAS 通过原子方式用新值 N 来更新 V 的值。如果不等,说明已经有其它线程更新了 V,则当前线程放弃更新。
JAVA 中如何实现 CAS
JAVA 中的 CAS 是通过底层的 Unsafe
类调用 CPU 的原子指令实现的。
- Java 使用
Unsafe.compareAndSwapXXX
方法实现 CAS;(xxx = int / long / Object
) - 这个方法由 JNI 调用到底层 C++代码;(通过 JNI 可以把 Java 调用“桥接”到 C/C++ 实现的底层函数上)
- 最终由 CPU 的原子指令(如 x86 的 CMPXCHG) 保证原子性。
CAS 存在的问题
- ABA:对一个值的两次读取之间值可能被修改过。解决思路是在变量前面追加上版本号或者时间戳。
悲观锁
悲观锁认为共享资源每次被访问的时候都会出现问题,所以每次获取资源时都会上锁,这样其他线程如果想拿到这个资源就会阻塞,直到锁被上一个持有者释放。
Java 中synchronized
和 ReentrantLock
等独占锁就是悲观锁思想的实现。
1 |
|
- 优点:实现简单,数据安全性强,适合写操作较多的场景,避免大量重试消耗资源。
- 缺点:高并发场景下激烈锁竞争会造成大量线程阻塞,大量线程阻塞会导致大量上下文切换,消耗大量系统资源。悲观锁甚至会导致死锁问题。
乐观锁和悲观锁
http://example.com/2025/04/15/乐观锁和悲观锁/