Java多线程中的CAS

多线程中的CAS


什么是CAS

CAS CompareAndSwap,或者 CompareAndSet,
是一个能够比较和替换的方法。
这个方法能够在多线程环境下保证对一个共享变量进行修改时的原子性不变。
通常,CAS方法会传递三个参数,
● 第一个参数V表示要更新的变量;
● 第二个参数E表示期望值;
● 第三个参数U表示更新后的值。

更新的方式是:
如果V==E ,表示预期值和实际值相等,则将 V修改成U 并返回 true,
否则修改失败返回false。

Created with Raphaël 2.3.0 开始 V==E? 更新变量V并设置值为U 返回true 不更新变量V 返回false yes no

CAS是如何实现的

在Java中的Unsafe类中提供了CAS方法,针对int类型变量的CAS方法定义如下:

public finlal native boolean compareAndSwapInt(Object o,long offset,int expect,int update);
它的四个参数:
● o,表示当前的实例对象
● offset,表示实例变量的内存地址偏移量
● expect,表示预期值
● update,表示要更新的值

compareAndSwapInt()是一个native方法,该方法是在JVM中定义和实现的。
基于compareAndSwapInt()方法,在JVM源码中的unsafe.cpp文件中,找到该方法:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  //将Java对象转化为JVM中的对象
  oop p = JNIHandles::resolve(obj);
  //根据offset计算value的地址
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  //比较addr和e是否相等,如果相等就把x赋值到目标字段,该方法返回修改之前的目标字段的值。
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

Atomic:compxchg() 方法的定义在atomic.cpp文件中:

unsigned Atomic::cmpxchg(unsigned int exchange_value,
                         volatile unsigned int* dest, unsigned int compare_value) {
  assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
  return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
                                       (jint)compare_value);
}

对于CAS操作,不同的操作系统和CPU架构,保证原子性的方法可能会不一样,而JVM是跨平台的语言,它需要在任何平台和CPU架构下都保持一致。Atomic:cmpxchg() 会在预编译阶段确定调用哪个平台下的重载。
在这里插入图片描述
以Linux为例,进入 atomic_linux_x86.inline.hpp中:

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  //判断是否多核CPU
  int mp = os::is_MP();
  //asm表示内嵌汇编代码
  //volatile通知编译器对访问该变量的代码不再进行优化
  //LOCK_IF_MP(%4)表示如果CPU是多核的,则需要为compxchgl指令增加一条Lock指令
  __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                    : "=a" (exchange_value)
                    : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                    : "cc", "memory");
  return exchange_value;
}

上述代码的功能是基于汇编指令cmpxchgl 从主内存执行比较及替换的操作来实现数据的变更。在多核心CUP的情况下,为了保证多核心CPU下执行该命令的原子性,会增加一个Lock指令。CAS的底层用到了锁的机制。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值