乐观锁和悲观锁
乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题。
- 乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
- 悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。
乐观锁本质上不是锁,而是通过其他方式对数据竞争问题进行求解;悲观锁一般通过上锁的方式解决数据竞争问题,适用的场合更多。
乐观锁两个解决方案:
- CAS
- 版本号机制
CAS
compare and swap。
- 需要读写的内存位置(V)
- 进行比较的预期值(A)
- 拟写入的新值(B)
CAS操作逻辑如下:如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。通过 CPU 的指令实现原子性。
版本号机制
对数据增加一个新的字段,通过对这个字段的解读判断数据是否被修改。其实是类似于 CAS,但是 CAS 关注的是数据的本身,可能存在 ABA 问题,而版本号机制就不会出现该问题。
适用场景
- 竞争不激烈:乐观锁,对于数据不会进行锁的操作,提升程序运行效率
- 竞争激烈:悲观锁,虽然锁会有性能损耗,但是竞争激烈情况下,乐观锁的实现会更麻烦
CAS 的缺点
- ABA 问题:当前的值已经经历过一次变动,但CAS无感知
- 高竞争的开销问题:CAS会不断的尝试,消耗CPU资源
- 功能限制:不支持多个变量的操作;需要CPU的支持