悲观锁和乐观锁

悲观锁和乐观锁

悲观锁

悲观锁是总会先去想最坏的情况,每次线程拿数据的时候都会认为他会进行修改,适用于的场景是多写少读,这时使用悲观锁效率会高。程序中典型的悲观锁时synchronized和ReentrantLock

乐观锁

乐观锁是总会先去想好的情况,每次线程拿数据只会看一眼,并不会做修改操作,这时没有必要加锁,程序中的atom原子类使用cas+volatile+native方法实现乐观锁。

两种锁的机制,有各自的好处,不能说谁好谁坏,各有优点:

悲观锁适用于多写少读的情况,而乐观锁适用于多读少写的情况,如果在多写的情况下使用乐观锁,会经常产生冲突,反而会降低性能。

乐观锁常用的两种方式

版本号的控制

每次读取数据的时候都会连同版本号一同读取,在当更新数据的时候,会比较读取到的版本号和数据库中的版本号是否一致,如果一致则更新,如果不一致则继续读取,更新数据。

CAS操作(compareAndSwap)

举个例子,在atomInteger类中涉及了CAS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x)
//这里是native方法 offset是偏移量先暂且不提,o是需要比较的值,expected是预期值,x是新值
// 如果使用程序写出来就是大概这样:
int value;
public boolean fakeCAS(int expect,int newValue){
if(value == expect){
value = newValue;
return true;
}else{
return false;
}
}

比较替换(compareAndSwap)是一个原子操作,也是一个自旋操作,等待一个周期再次尝试。

CAS操作的缺点

  1. ABA问题,何谓ABA:当两个线程读取到当前值为A,其中一个线程把值改为B后再把B改为A,这是另外一个线程使用cas操作读取到的值仍然是A,CAS会认为这个值从来没有变过,这就是ABA问题。也就是说遗失掉中间的过程,在链式的操作总更能体会到ABA问题的严重性。
  2. 自旋时间过长,消耗CPU资源。
  3. 只能对单个共享变量的原子性操作
-------------本文结束感谢您的阅读-------------

本文标题:悲观锁和乐观锁

文章作者:NanYin

发布时间:2019年04月23日 - 12:04

最后更新:2019年08月12日 - 13:08

原始链接:https://nanyiniu.github.io/2019/04/23/2019-04-08-%E6%82%B2%E8%A7%82%E9%94%81%E5%92%8C%E4%B9%90%E8%A7%82%E9%94%81/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。