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上的锁性能好很多。