继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

OpenJDK系列(三):JVM对CAS的设计与实现

青春有我
关注TA
已关注
手记 1239
粉丝 205
获赞 1008

CAS简介

CAS即Compare-and-Swap的缩写,即比较并交换,它是一种实现乐观锁的技术.在CAS中包含三个操作数:

  • V: 需要读写的内存位置,从java角度你可以把它当成一个变量

  • A: 预期值,也就是要进行比较的值

  • B: 拟写入的新值

当且仅当V的值等于A时,CAS才会通过原子方式用新值B来更新V的值,否则不会执行任何操作.无论位置V的值是否等于A,最终都会返回V原有的值.换句话说:"我认为V的值应该是A,如果是,那么就将V的值更新为B,否则不修改并告诉V的实际值是多少".

当多个线程使用CAS同时更新同一个变量时,只有其中一个线程能够成功更新变量的值,其他线程都将失败.和锁机制不同,失败的线程并不会被挂起,而是告知用户当前失败的情况,并由用户决定是否要再次尝试或者执行其他操作,其典型的流程如下:

webp

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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP