定义
CAS操作包含三个操作数-内存位置(V)、期望值(A)和新值(B)
如果内存位置的值与期望值匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不作任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。
(CAS在一些特殊情况下仅返回CAS是否成功,而不提取当前值)CAS有效的说明了
“我认为位置V应该包含值A:如果包含该值,则将B放到这个位置;否则,不要更改该位置的值,只告诉我这个位置现在的值即可。”
写一个简易CAS锁
package concurrent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Demo1 {
static int count = 0;
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
int threadSize = 100;
//保证100个线程之后再执行后边的代码
CountDownLatch countDownLatch = new CountDownLatch(threadSize);
for (int i = 0; i < threadSize; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
request();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}
});
thread.start();
}
//保证100个线程之后再执行后边的代码
countDownLatch.await();
long endTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+",耗时:"+(endTime-startTime)+",count="+count);
}
public static synchronized boolean compareAndSwap(int expectCount,int newCount){
if (expectCount==getCount()){
count = newCount;
return true;
}
return false;
}
public static int getCount(){
return count;
}
public static void request() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(5);
//count ++操作实际上是由3步来完成!(jvm执行引擎)
//1,获取count的值,记做A:A-count
//2.将A值+1,得到B:B-A+1
// 3,将B值赋值给count
//升级第3步的实现:
//1,获取锁
//2.获取以Fcount最新的值,记做LV
//3,判断LV是否等于A,如果相等,则将B的值赋值给count,并返回true,否则返回false
//4.释放锁
//count++; 改为如下操作
int expectCont;
while (!compareAndSwap(expectCont=getCount(),expectCont+1)){};
}
}
java中提供了对CAS操作的支持,具体在sun.misc.unsafe类
//参数var1:表示要操作的对象
//参数var2:表示要操作对象中属性地址的偏移量
//参数var4:表示需要修改数据的期望的值
//参数var5:表示需要修改为的新值
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);
CAS实现原理
CAS通过调用JNT的代码实现,JNI:java Native Interface,允许java调用其它语言。而compareAndSwapxxx系列的方法就是借助"C语言”来调用cpu底层指令实现的。
以常用的Intel x86平台来说,最终映射到的cpu的指令为"cmpxchg",这是一个原子指令,cpu执行此命令时,实现比较并替换的操作!
现代计算机动不动就上百核心,cmpxchg怎么保证多核心下的线程安全?
系统底层进行CAS操作的时候,会判断当前系统是否为多核心系统,如果是就给“总线”加锁,只有一个线程会对总线加锁成功,加锁成功之后会执行CAS操作,也就是说CAS的原子性是平台级别的!
compareAndSet函数
//expectedReference:期望引用
//newReference:新值引用
//expectedStamp:期望引用的版本号
//newStamp:新值版本号
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
//期望引用与当前引用一致
expectedReference == current.reference &&
//期望版本与当前版本一致
expectedStamp == current.stamp &&
(
//如果新的修改引用与当前引用 新的版本与当前版本一致,就不用创建新的Pair对象
(newReference == current.reference &&
newStamp == current.stamp) ||
//创建新的Pair对象
casPair(current, Pair.of(newReference, newStamp))
);
}