JDK8的CAS在linux及x86汇编的实现及分析

首先贴下jdk8里面java的native方法的声明,在文件 jdk.internal.misc.Unsafe.java 里面:

   /**
     * Atomically updates Java variable to {@code x} if it is currently
     * holding {@code expected}.
     *
     * <p>This operation has memory semantics of a {@code volatile} read
     * and write.  Corresponds to C11 atomic_compare_exchange_strong.
     *
     * @return {@code true} if successful
     */
    @HotSpotIntrinsicCandidate
    public final native boolean compareAndSetInt(Object o, long offset,
                                                 int expected,
                                                 int x);

这个方法原子性的更新变量的值为x如果原来的值是期待的expected的值时。

jdk8里面native(c++)代码的实现,在文件 src/share/vm/prims/unsafe.cpp

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
  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

其中UNSAFE_ENTRY和UNSAFE_END是定义的两个宏,暂时不做分析

上面的方法主要有三个逻辑:

  1. oop p = JNIHandles::resolve(obj);//获取obj这个对象在jvm里面的对应的内存对象实例
  2. jint* addr = (jint *)index_oop_from_field_offset_long(p, offset);//通过上面的内存对象实例结合传入的偏移量获取字段对应内存对象字段在对象里面的偏移的地址,可以看到是一个int的指针。
  3. return (jint)(Atomic::cmpxchg(x, addr, e)) == e;//通过调用原子方法的结果判断返回值是不是原来的e值,如果是表示更新成功,否则更新失败。

下面分析Atomic::cmpxchg(x, addr, e)方法的具体实现:
这个方法在atomic_linux_x86.hpp文件里面,不同的系统不同的cpu架构对应不同的实现代码及文件,这里以linux x86架构分析。

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value, cmpxchg_memory_order order) {
  int mp = os::is_MP();
  __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;
}

方法主要以内联汇编的形式组织代码,并且加了volatile防止编译器gcc进行指令优化,保证编写的汇编代码的执行顺序于编写的顺序一致。关于c++内联汇编可以参考:GCC内联汇编基础

现在分析下这个汇编代码的逻辑:

  1. 首先分析下汇编指令的操作码cmpxchgl,指令cmpxchg后面加了一个后缀l在at&t的汇编风格表示操作的操作数的字长为双子即32位,和l类似的是b和w,分别表示字节(8位)和字(16位)。
  2. 汇编指令格式,at&t风格: 操作码 源操作数 目的操作数。
  3. 指令的作用是:CMPXCHG r,r/m 。 将累加器AL/AX/EAX/RAX中的值与目的操作数比较,如果相等,源操作数的值装载到目的操作数,zf置1。如果不等,目的操作数的值装载到AL/AX/EAX/RAX并将zf清0。
  4. 结合这里的例子,可以看到:%1是源操作数,(%3)是首操作数,compare_value的值是被比较的值,通过"a" (compare_value)放入寄存器eax,
    cmpxchgl %1,(%3)比较第三个变量(%3)这个是at&t的风格类似intel风格[%3],这里表示内存为dest偏移量的地址的值。指令比较的时候:首先把compare_value赋值给eax,然后比较eax和(%3)里面的值,如果(%3)的值和eax相等,就把%1的值装载到(%3)里面,这时(%3)里面的值为exchange_value,如果不等就把(%3)里面的值装载到寄存器eax里,同时把寄存器eax的输出到绑定的exchange_value变量上。这个方法最后返回的是exchange_value。结合前面调用的方法可以看到如果成功更新,则变量exchange_value的值是之前内存的值,如果更新失败则是原来的值。
  5. 再分析一下代码里面的前两行:int mp = os::is_MP(); LOCK_IF_MP(%4) ;
    第一行就是判断当前系统是否是多核的,第二行代码通过前面的变量mp(%4就是mp)判断是否是多核,如果是就加上lock指令前缀。关于locklock指令前缀:
    在多处理器环境中,LOCK#信号可确保在断言该信号时处理器拥有对任何共享内存的独占使用。

总结:

  1. 首先是通过lock保证操作的内存行具有cpu独占性;
  2. 通过cmpxchg命令来进行原子比较交换操作;
  3. 在c++里面通过内联汇编的方式同时加上volatile让gcc不进行编译优化保证汇编代码执行的顺序。
  4. 综上,通过以上三点最终保证了在多核cpu上面cas执行的原子性。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容