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 执行自增操作。

  1. 两个线程都读取 value 的值到 oldValue(预期值)中:
    线程1的预期值:0,要设置的新值:预期值 + 1。
    线程2的预期值:0,要设置的新值:预期值 + 1。
    在这里插入图片描述

  2. 假设线程1先执行CAS操作,预期值与内存中的值相等,执行 + 1操作。
    在这里插入图片描述

  3. 线程2再执行CAS操作,发现内存中的值和预期值不相等,不能进行+1操作。进入循环,线程2重新读取 value 的值到 oldValue(预期值)中。
    在这里插入图片描述

  4. 线程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. 线程1和线程2都获取到当前的余额为20000,都期望更新为10000。
  2. 线程1先执行,预期值与内存中的20000相等,执行扣款操作。
  3. 在线程2执行之前,我爸爸又给我的账户转了10000,现在账户余额依旧是20000.
  4. 线程2执行,预期值20000与内存中的20000相等,执行扣款操作。

这样就出现了问题,出现了重复扣款的情况,那我肯定不能愿意啊😳

3. 解决ABA问题
我们给要修改的值,加一个版本号,在预期值与内存中的值进行比较的时候,版本号也需要进行比较,只要版本号不一样,就代表数据已经被修改过了。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐