您的位置:首页 > 其它

CAS原理分析

2016-07-25 16:13 309 查看
CAS

CAS:Compare and Swap, 翻译成比较并交换。

在java.util.concurrent大量使用了CAS算法来实现非阻塞并发。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。

当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。下面看下Java并发包中的原子类是如何实现。

private volatile int value;
public final int get() {
return value;
}
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

compareAndSet(int expect, int update),


在这里采用了CAS操作,每次从内存中读取数据然后将此数据和+1后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止。

而compareAndSet利用JNI来完成CPU指令的操作.整体的过程就是这样子的,利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法。

其它原子操作都是利用类似的特性完成的,其中unsafe.compareAndSwapInt(this, valueOffset, expect, update);是Unsafe中的一个Native方法。

可以看出,到此为止与Java实现相关的都到这里结束了。下面看看这个Native方法,该方法底层是用C++实现:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p = JNIHandles::resolve(obj);
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END


这里实际调用的是cmpxchg(x, addr, e),这个函数涉及到了Cpu架构指令,网上找了这个函数的代码,可以看出在这个函数中已近嵌入了汇编代码了,也就是说CAS是在CPU指令级别实现的。

inline jint    Atomic::cmpxchg    (jint   exchange_value, volatile jint*  dest, jint   compare_value) {
// alternative for InterlockedCompareExchange
int mp = os::is_MP();
__asm {
mov edx, dest
mov ecx, exchange_value
mov eax, compare_value
LOCK_IF_MP(mp)
cmpxchg dword ptr [edx], ecx
}
}


CAS虽然能够实现高效并发,而且JDK并发包中很多类都使用了CAS来实现非阻塞并发,CAS也是有一定的缺点,常见的ABA问题已经可以通过版本号来解决,但是如果CAS一直不成功

那么将会严重耗费CPU资源。

(完)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: