CAS简介说明
下文笔者讲述CAS简介说明,如下所示
CAS简介
CAS:
其英文缩写为(Compare And Swap),其功能就是比较和交换,是CPU支持的一种内存交换指令
此指令会对内存中共享数据进行操作,它对内存中的共享数据进行原子操作
主要用于先判断新值是否发生变化,不相同则不做更新
主要事项:
1.CAS是一种无锁的实现模式,它是一种乐观锁的实现模式,
它可保证多线程并发中保障共享资源的原子性操作(相对于synchronized或Lock是一种轻量级的实现)
2.jdk中有一些原子类,如:
AtomicInteger、CurrentHashMap
AtomicInteger使用说明
未使用AtomicInteger类的原子类实现
public class ThreadSafeTest {
public static volatile int i = 0;
public synchronized void increase() {
i++;
}
}
基于AtomicInteger类的实现
public class ThreadSafeTest {
private final AtomicInteger counter = new AtomicInteger(0);
public int increase(){
return counter.addAndGet(1);
}
}
AtomicInteger类简介
AtomicInteger是 java.util.concurrent.atomic包下的一个原子类 该包下还有AtomicBoolean, AtomicLong,AtomicLongArray, AtomicReference等原子类 主要用于在高并发环境下,保证线程安全。
AtomicInteger常用API
AtomicInteger类提供了如下常见的API功能: public final int get():获取当前的值 public final int getAndSet(int newValue):获取当前的值,并设置新的值 public final int getAndIncrement():获取当前的值,并自增 public final int getAndDecrement():获取当前的值,并自减 public final int getAndAdd(int delta):获取当前的值,并加上预期的值 void lazySet(int newValue): 最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
AtomicInteger核心源码
public class AtomicInteger extends Number implements java.io.Serializable {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
// 用于获取value字段相对当前对象的“起始地址”的偏移量
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
//返回当前值
public final int get() {
return value;
}
//递增加detla
public final int getAndAdd(int delta) {
// 1、this:当前的实例
// 2、valueOffset:value实例变量的偏移量
// 3、delta:当前value要加上的数(value+delta)。
return unsafe.getAndAddInt(this, valueOffset, delta);
}
//递增加1
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
...
}
AtomicInteger底层 通过volatile变量和CAS两者相结合来保证更新数据的原子性
CAS的工作原理
CAS的实现原理: 是由Unsafe类和其中的自旋锁来完成
UnSafe类
sun.misc.Unsafe是JDK内部用的工具类 它通过暴露一些Java意义上说“不安全”的功能给Java层代码 来让JDK能够更多的使用Java代码来实现一些原本是平台相关的 需要使用native语言(C或C++)才可以实现的功能 该类不应该在JDK核心类库之外使用
Unsafe类的功能
Unsafe类的功能: 内存操作、CAS、Class相关、对象操作、数组相关、内存屏障、系统相关、线程调度等功能
Unsafe类常见方法
Unsafe类拥有
objectFieldOffset()方法:
用于获取某个字段相对Java对象的“起始地址”的偏移量
getInt、getLong、getObject等方法:
可以使用前面获取的偏移量来访问某个Java对象的某个字段
例:
AtomicInteger中的static代码块 使用objectFieldOffset()方法
Unsafe与CAS
AtomicInteger调用Unsafe#getAndAddInt方法
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
AtomicInteger调用UnSafe类的CAS方法
JVM实现汇编指令,从而实现原子操作
在Unsafe中getAndAddInt方法实现如下
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
getAndAddInt方法有三个参数:
第一个参数表示当前对象,也就是new的那个AtomicInteger对象;
第二个表示内存地址;
第三个表示自增步伐,
在AtomicInteger#incrementAndGet中默认的自增步伐是1
getAndAddInt方法中
先把当前对象主内存中的值赋给val5
然后进入while循环。判断当前对象此刻主内存中的值是否等于val5
如果是,就自增(交换值),否则继续循环,重新获取val5的值
注意事项:
1.compareAndSwapInt方法,是一个native方法
这个方法汇编之后是CPU原语指令
原语指令是连续执行不会被打断的
所以可以保证原子性
2.getAndAddInt方法中还涉及到一个实现自旋锁
自旋的概念指:getAndAddInt方法中的do while循环操作
当预期值和主内存中的值不等时
就重新获取主内存中的值
3.CAS缺点:
内部使用自旋的方式进行CAS更新(
while循环进行CAS更新,如果更新失败,则循环再次重试)
当长时间都不成功的话,就使CPU开销变大
4.Unsafe类还支持其他的CAS方法,如compareAndSwapObject、compareAndSwapInt、compareAndSwapLong
CAS缺点
我们都知道使用CAS可实现原子性操作,但是它还具有以下缺点,如下所示1.长时间未运行完毕,则会产生CPU开销大 2.由于只保证共享变量的原子操作,则会产生ABA问题
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


