CAS定义
check then act
的两个动作,这两个动作在在硬件的处理器上是具备原子性,也就是在操作系统底层上已经实现对CAS算法的原子性保证CAS 使用条件
CAS之简易版本
// 简单的check方式完成对象新值的设置
// cas.java
boolean cas(Object ref, int refOldVal, int refNewVal){
if(ref.value != refOldVal) return false;
ref.value = refNewVal;
return true;
}
// cas_adder.java
// import cas.java
int cas_adder(Object ref, int incr){
while(!cas(ref, ref.value, ref.value+incr)){
// nothing
}
// 表示修改成功
return ref.value;
}
java原子操作类Atomic*实现
// AtomicBoolean.java 摘取核心代码
public class AtomicBoolean implements java.io.Serializable {
private static final long serialVersionUID = 4654671469794556979L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
// 使用volatile修饰,保证修改的可见性,令当前的线程缓存失效,读取主内存修改后的数据
private volatile int value;
static {
try {
// 获取当前属性value的内存地址偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicBoolean.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0;
int u = update ? 1 : 0;
// 使用unsafe的CAS方法完成修改操作
return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
}
// AtomicDefineInt.java
public class AtomicDefineInt {
private volatile int value;
private static final Unsafe unsafe;
// 定义内存偏移量
private static final long iValueOffset;
static {
try {
// 必须通过反射获取Unsafe,本身是属于不安全的一个操作,直接通过getUnsafe会抛出异常,
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
// 从JNI中获取value属性在堆内存中的地址偏移量
iValueOffset = unsafe.objectFieldOffset(AtomicDefineInt.class.getDeclaredField("value"));
}catch (NoSuchFieldException e){
throw new RuntimeException(e);
}
}
// 借助UnSafe调用CAS方法完成操作
public boolean compareAndSet(int expect, int update){
return unsafe.compareAndSwapInt(this, iValueOffset, expect, update);
}
}
Unsafe源码以及实现
// java代码
public final class Unsafe {
// 字段属性theUnsafe
private static final Unsafe theUnsafe;
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
// 只允许jvm调用,java程序无法直接调用
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
// compareAndSwapInt的修改方法为native
// 表示在线程的虚拟机栈中加载调用方法,由c++底层源码实现
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
}
// c++代码
// 核心方法
// 获取内存偏移量
UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset0(JNIEnv *env, jobject unsafe, jobject field)) {
return find_field_offset(field, 0, THREAD);
} UNSAFE_END
// 完成CAS操作
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
// JNI解析加载java object
oop p = JNIHandles::resolve(obj);
if (p == NULL) {
// 如果p不是java中定义的面向对象引用,直接从内存地址完成修改操作
volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset);
return RawAccess<>::atomic_cmpxchg(addr, e, x) == e;
} else {
// 如果p是java对象,直接在堆内存中对p的属性数据进行修改操作
assert_field_offset_sane(p, offset);
return HeapAccess<>::atomic_cmpxchg_at(p, (ptrdiff_t)offset, e, x) == e;
}
} UNSAFE_END
CAS问题
ABA问题
// AtomicDefineObject
public final class AtomicDefineObject implements Serializable {
private volatile String value;
private static Unsafe unsafe;
private static final long valueOffset;
static {
try {
// 反射获取
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
valueOffset = unsafe.objectFieldOffset(AtomicDefineObject.class.getDeclaredField("value"));
}catch (NoSuchFieldException | IllegalAccessException e){
throw new RuntimeException(e);
}
}
private boolean compareAndSet(String expect, String update){
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
public void setValue(String value){
this.compareAndSet(this.value, value);
}
public String getValue() {
return value;
}
}
main(){
final AtomicDefineObject atomicDefineObject = new AtomicDefineObject();
atomicDefineObject.setValue("A");
System.out.println(Thread.currentThread() + " --- set value to A----");
Thread t1 = new Thread("thread1"){
@Override
public void run() {
try{
// 完成写操作需要1s
TimeUnit.SECONDS.sleep(1L);
atomicDefineObject.setValue("B");
System.out.println(Thread.currentThread() + " --- set value to B----");
}catch (Exception e){}
}
};
Thread t2 = new Thread("thread2"){
@Override
public void run() {
try{
// 完成写操作需要2s
TimeUnit.SECONDS.sleep(2L);
atomicDefineObject.setValue("A");
System.out.println(Thread.currentThread() + " --- set value to A----");
}catch (Exception e){}
}
};
Thread t3 = new Thread("thread3"){
@Override
public void run() {
try{
// 由于网路原因,读取操作延迟
TimeUnit.SECONDS.sleep(3L);
String val = atomicDefineObject.getValue();
System.out.println(Thread.currentThread() + " --- get value ----" + val);
}catch (Exception e){}
}
};
// start && join
}
Thread[main,5,main] --- set value to A----
Thread[thread1,5,main] --- set value to B----
Thread[thread2,5,main] --- set value to A----
Thread[thread3,5,main] --- get value ----A
finish task dome ...
## 最终读线程读取到的数据是A,但是不知道之前对象已经发生过修改操作,对当前读操作是一个透明
ABA解决方案
感谢花时间阅读,如果有用欢迎转发或者点个好看,谢谢!