CAS也是锁

52次阅读

共计 1143 个字符,预计需要花费 3 分钟才能阅读完成。

CAS(CompareAndSwap)顾名思义比较再交换。先比较,发现与预期一致,说明没有其他线程改动过,于是就交换;如果不一致说明改动过,就再来一次,如此往复。

int prev, next;
do {prev = get();
    next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;

这是一种自旋的方式保证线程安全,可是 compareAndSet 这个比较再交换是原子的吗?先比较发现与预期一致了,准备交换的时候另一个线程来改了怎么办?
点进去看源码:

public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

这个 unsafe 的方法都是 native 方法,

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

只能打开 openJDK 看源码了

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 方法

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
  }
}

原来 LOCK_IF_MP 这里加了锁,才保证了原子性。所谓“无锁”是在 Java 层面上没有锁,但其实在操作系统的 CPU 指令层面是加了锁的。这个锁比 java 上的锁性能好很多。

正文完
 0