Java中的CAS
CAS
CAS全称是Compare-and-Swap,翻译中文是比较并交换
,是并发编程中一种常用的算法。Java中concurrent包完全建立在CAS上。我们常见并发控制是使用锁,这是一种悲观的策略,假设每次对资源访问都会发生冲突,所以当有一个线程访问资源时,其他线程就必须等待。与之相反的时乐观的策略,假设线程对资源的访问是没有冲突的,同是所有线程执行都不需要等待,如果遇到冲突,就会使用CAS来鉴别冲突,如果鉴别到冲突,就重试当前操作直到没有冲突为止。
CAS的大概执行步骤:
- 1、读取内存中某个变量的值为一个临时变量;
- 2、对内存中某个变量的值进行一系列操作;
- 3、判断临时值与内存中某个变量的值是否相等,如果相等则没有别修改过,那么将上面步骤2的操作结果写入;不相等则是被其他线程修改过,此时放弃或者从步骤1开始重试。
步骤3就是比较替换,这个步骤是需要原子性,不然无法保证比较操作之后其它线程的影响。
Unsafe
Java中无法直接访问底层操作系统,必须通过本地方法(Native)来进行访问。即提供了Unsafe类,该类里面提供了大量Native方法,来支持硬件级别的原子操作。尽管这个类里卖弄的方法都是public的,但是我们不能使用它,官方也不建议我们使用。
这是Unsafe类中CAS操作相关的方法:
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
更多关于Unsafe类的知识自行查阅资料。
CAS的缺点
-
ABA问题
CAS操作的时候需要检查值有没有发生改变,但是如果有两个线程1、2对变量V进行操作,线程2获取的获取的变量V的值是A,但是线程1将V的值先修改为B,后面又修改为A,此时线程2去更新时比较变量V的值还是A,所以线程2发现值没有改变,但实际上值发生了改变。
-
循环时间开销
重试长时间不成功,会给CPU带来非常大的执行开销。
-
只能保证一个共享变量的原子操作
Java中CAS操作只是对CPU指令的一层封装,一次只能原子操作一个变量。