【多线程】 -- CAS
1. CAS
CAS(Compare-And-Swap),“比较并交换”。
CAS伪代码:
boolean CAS(address, expectValue, swapValue) {
if (&address == expectedValue) {
&address = swapValue;
return true;
}
return false;
}
参数说明:
1. address:表示要修改的内存地址。
2. expectValue:表示预期值。
3. swapValue:表示要设置的新值。
执行流程:
1. 用预期值和内存地址中的值作比较。
2. 如果相等,就用新的值更新内存中的值。
3. 如果不相等,就进入下一次比较。
2. CAS是如何保证线程安全的?
下面假设:两个线程对一个 value 执行自增操作。
-
两个线程都读取 value 的值到 oldValue(预期值)中:
线程1的预期值:0,要设置的新值:预期值 + 1。
线程2的预期值:0,要设置的新值:预期值 + 1。
-
假设线程1先执行CAS操作,预期值与内存中的值相等,执行 + 1操作。

-
线程2再执行CAS操作,发现内存中的值和预期值不相等,不能进行+1操作。进入循环,线程2重新读取 value 的值到 oldValue(预期值)中。

-
线程2再一次执行CAS,内存中的值和预期值相等,执行 +1 操作。

自旋锁是通过CAS实现的,只不过是在JVM层面实现的,并不涉及真实的LOCK指令。自旋就是通过while把CAS包裹,让CAS没有成功的时候不断的执行,直到成功执行为止。这个while就相当于是在用户态实现的锁,是一个轻量级锁。
CAS操作是直接修改主内存中的值,读取–>比较–>修改,这些操作对应到的是CPU上的一个指令:cmpxchg。
3. CAS的ABA问题
1. 什么是ABA问题?
CAS在执行时,预期值发生了两次变化,一次变成了另外一个值,一次又变了回来(A 被改成了 B,B又被改成了A)。
2. ABA问题可能造成的问题?
假设要交学费了:线程1和线程2并发的来执行扣款操作,我的账户余额20000(假设哈,只是假设),学费是10000。
- 线程1和线程2都获取到当前的余额为20000,都期望更新为10000。
- 线程1先执行,预期值与内存中的20000相等,执行扣款操作。
- 在线程2执行之前,我爸爸又给我的账户转了10000,现在账户余额依旧是20000.
- 线程2执行,预期值20000与内存中的20000相等,执行扣款操作。
这样就出现了问题,出现了重复扣款的情况,那我肯定不能愿意啊😳
3. 解决ABA问题
我们给要修改的值,加一个版本号,在预期值与内存中的值进行比较的时候,版本号也需要进行比较,只要版本号不一样,就代表数据已经被修改过了。
更多推荐


所有评论(0)