悲观锁和乐观锁
传统的锁机制,例如使用java的关键字被认为是一种悲观锁技术。悲观锁首先要求没有其他的线程能够干扰确定的操作(锁定对象),然后才允许你接入实例或者使用方法
这就好像说:“请先把门关上,否则会有其他的骗子进来”。
虽然使用synchronized方法很安全,但是这种方式是以牺牲性能来换群的安全。理由很简单,在线程等待锁的时候,线程什么也不会做。
相比较传统的悲观锁,还有一种高性能的乐观锁机制。可以通过希望在没有任何干扰的情况下完后一个update(升级?)。这个操作依赖冲突检测,如果在升级的过程中被其他的线程干扰了,操作将会失败,然后退出。
Compare and Swap就是乐观锁的一个很好的例子
CAS 算法
算法思路:通过比较一个给定值(A)和内存中某个位置的值(V),如果值两个值相等,那么久修改内存中的值为一个传递进来的新的值(B)。这是一个原子操作。原子性保障了新的值是基于更新信息的值(B)。如果在同一个时刻内,内存中的值(V)被其他的线程修改过了,那么当前线程修改内存值操作就会失败。操作的结果需要显示内存的值是否被替换;这个可以通过一个返回一boolean变量来实现
CAS算法的3个参数
- 内存中的值V(将被替换的值)
- 线程上一次读取到的值A
- 将会替换内存中的值B
CAS大致过程:内存中的值应该是A,如果是那么我们用B来替换A,否则就不改变内存的值并且返回false。
CAS是一种乐观锁,它希望可以升级成功;同时也可以检测到失败如果和其上一次检测到的数据不一样(有其他线程修改了变量)
例子
假设V是内存中存储的值为10;现在有多个线程想要增加这个值;
- Thread1和Thread2想要增加V的值,
V = 10,A= 0,B= 0 - 线程1首先到达然后比较V的值和其上一次读取到的值是否相同
V = 10, A= 10,B= 11
if(A == V){
V = B;
}else{
//操作失败
返回V
}
很显然,Thread1上一次读取到的值A和V相等,因此V被置为11
- Thread2也执行到这里了,执行与Thread1相同的操作
V = 11,A = 10,B = 11
if(A == V){
V = B;
}else{
//操作失败
返回V
}
这种情况下,V不等于A,因此修改失败,然后返回V的值给Thread2,现在Thread2继续执行上面的操作,这个时候执行会成功,然后返回V=12给Thread2
总结
当多个线程同时尝试使用CAS算法去修改同一个变量时,其中只会有一个线程成功,其他线程会失败。但是修改失败的线程不会不会暂停,这些线程可以再一次去执行CAS修改或者什么也不做。
翻译文章
https://howtodoinjava.com/core-java/multi-threading/compare-and-swap-cas-algorithm/