CAS简介
CAS即Compare-and-Swap的缩写,即比较并交换,它是一种实现乐观锁的技术.在CAS中包含三个操作数:
V: 需要读写的内存位置,从java角度你可以把它当成一个变量
A: 预期值,也就是要进行比较的值
B: 拟写入的新值
当且仅当V的值等于A时,CAS才会通过原子方式用新值B来更新V的值,否则不会执行任何操作.无论位置V的值是否等于A,最终都会返回V原有的值.换句话说:"我认为V的值应该是A,如果是,那么就将V的值更新为B,否则不修改并告诉V的实际值是多少".
当多个线程使用CAS同时更新同一个变量时,只有其中一个线程能够成功更新变量的值,其他线程都将失败.和锁机制不同,失败的线程并不会被挂起,而是告知用户当前失败的情况,并由用户决定是否要再次尝试或者执行其他操作,其典型的流程如下:
image-20180910121551030
传统锁实现CAS语义
在明白CAS的语义后,我们用传统的锁机制来实现该语义.
public class SimpleCAS { private int value; public int getValue() { return value; } // 比较并交换语义,最终都返回原有值 public synchronized int compareAndSwap(int exectedValue, int newValue) { int oldValue = value; if (oldValue == exectedValue) { value = newValue; } return value; } // 比较并设置语义,返回成功与否 public synchronized boolean compareAndSet(int exectedValue, int newValue) { return exectedValue == compareAndSwap(exectedValue, newValue); } }
在上述代码中,compareAndSwap()
用于实现"比较并交换"的语义,在此之上我们还实现了"比较并设置"的语义.
使用场景
CAS典型使用模式是:首先从V中读取值A,并根据A计算出新值B,然后再通过CAS以原子方式将V中的值变成B(如果在此期间没有任何线程将V的值修改为其他值).我们借助刚才的SimpleCAS实现一个计数器,借此来说明其使用场景:
// 线程安全的计数器public class SafeCounter { private SimpleCAS cas; public SafeCounter() { this.cas = new SimpleCAS(); } public int getValue() { return cas.getValue(); } public int increment() { int value; int newValue; do { // 读取旧值A value = cas.getValue(); // 根据A计算新值B newValue = value + 1; } while (!cas.compareAndSet(value, newValue));// 使用CAS来设置新值B return newValue; } }
SafeCounter不会阻塞,如果其他线程同时更新计数器,那么会执行多次重试操作直至成功.到现在有关CAS的语义和使用已经说完,下面我们要说的是CAS在JAVA中的应用以及JVM中如何实现CAS.
CAS实现
通过传统的锁实现的CAS语义并非JVM真正对CAS的实现,这点需要记住.JVM中能够实现CAS本质是现代CPU已经支持Compare-and-Swap指令.从Java 5.0开始,JVM中直接调用了相关指令.
JVM对CAS的支持
有关原子性变量的操作被统一定义在atomic.hpp,并以模板方法提供,其路径为:
/OpenJDK10/hotspot/src/share/vm/runtime/atomic.hpp
template<typename T, typename D, typename U>inline D Atomic::cmpxchg(T exchange_value, D volatile* dest, U compare_value, cmpxchg_memory_order order) { return CmpxchgImpl<T, D, U>()(exchange_value, dest, compare_value, order); }template<typename T>struct Atomic::CmpxchgImpl< T, T, T, typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::value>::type> VALUE_OBJ_CLASS_SPEC { T operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order order) const { // Forward to the platform handler for the size of T. return PlatformCmpxchg<sizeof(T)>()(exchange_value, dest, compare_value, order); } };
不同的平台PlatformCmpxchg实现不同,比如在mac平台上,其实现在
/OpenJDK10/hotspot/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.hpp
// 1字节长度template<typename T>inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order /* order */) const { STATIC_ASSERT(1 == sizeof(T)); // 内嵌汇编代码,最终调用cmpxchgb指令实现"比较并交换" __asm__ volatile ( "lock cmpxchgb %1,(%3)" : "=a" (exchange_value) : "q" (exchange_value), "a" (compare_value), "r" (dest) : "cc", "memory"); return exchange_value; }// 4字节长度template<typename T>inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order /* order */) const { STATIC_ASSERT(4 == sizeof(T)); __asm__ volatile ( "lock cmpxchgl %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) : "cc", "memory"); return exchange_value; }// 8字节长度template<typename T>inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order /* order */) const { STATIC_ASSERT(8 == sizeof(T)); __asm__ __volatile__ ( "lock cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest) : "cc", "memory"); return exchange_value; }
在window_x86平台中,其实现在/OpenJDK10/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.hpp
template<>template<typename T>inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order order) const { STATIC_ASSERT(1 == sizeof(T)); // alternative for InterlockedCompareExchange // 内嵌汇编代码,最终调用cmpxchg指令实现"比较并交换" __asm { mov edx, dest mov cl, exchange_value mov al, compare_value lock cmpxchg byte ptr [edx], cl } }template<>template<typename T>inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order order) const { STATIC_ASSERT(4 == sizeof(T)); // alternative for InterlockedCompareExchange __asm { mov edx, dest mov ecx, exchange_value mov eax, compare_value lock cmpxchg dword ptr [edx], ecx } }template<>template<typename T>inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value, T volatile* dest, T compare_value, cmpxchg_memory_order order) const { STATIC_ASSERT(8 == sizeof(T)); jint ex_lo = (jint)exchange_value; jint ex_hi = *( ((jint*)&exchange_value) + 1 ); jint cmp_lo = (jint)compare_value; jint cmp_hi = *( ((jint*)&compare_value) + 1 ); // 内嵌汇编代码,最终调用cmpxchg8b指令实现"比较并交换"8字节 __asm { push ebx push edi mov eax, cmp_lo mov edx, cmp_hi mov edi, dest mov ebx, ex_lo mov ecx, ex_hi lock cmpxchg8b qword ptr [edi] pop edi pop ebx } }
作者:涅槃1992
链接:https://www.jianshu.com/p/f009da2e4110
共同学习,写下你的评论
评论加载中...
作者其他优质文章