专栏首页软件开发-青出于蓝openJDK之sun.misc.Unsafe类CAS底层实现

openJDK之sun.misc.Unsafe类CAS底层实现

注:这篇文章参考了https://www.cnblogs.com/snowater/p/8303698.html,而后自己结合hotspot源码看的

1.sun.misc.Unsafe中CAS方法

在sun.misc.Unsafe中CAS方法如下:

  1. compareAndSwapObject(java.lang.Object arg0, long arg1, java.lang.Object arg2, java.lang.Object arg3);
  2. compareAndSwapInt(java.lang.Object arg0, long arg1, int arg2, int arg3);
  3. compareAndSwapLong(java.lang.Object arg0, long arg1, long arg2, long arg3);

来看下openJDK8的hotspot中,unsafe是如何实现的,链接http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/prims/unsafe.cpp

                                                                    图1

List-1

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
  UnsafeWrapper("Unsafe_CompareAndSwapObject");
  oop x = JNIHandles::resolve(x_h);//更新后的值
  oop e = JNIHandles::resolve(e_h);//期望值
  oop p = JNIHandles::resolve(obj);//更新的对象
  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);//获取偏移地址,可以理解为获取要更新的属性的内存地址
  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);//调用方法执行CAS操作
  jboolean success  = (res == e);//atomic_compare_exchange_oop的返回值是否等于期望值,如果等于,则success为true
  if (success)
    update_barrier_set((void*)addr, x);//更新memory barrier
  return success;
UNSAFE_END

    atomic_exchange_oop声明在http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/oops/oop.hpp中,如下

List-2

  static oop atomic_compare_exchange_oop(oop exchange_value,
                                         volatile HeapWord *dest,
                                         oop compare_value,
                                         bool prebarrier = false);

    实现在http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/oops/oop.inline.hpp中,如下List-3所示:

List-3

inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
                                                volatile HeapWord *dest,
                                                oop compare_value,
                                                bool prebarrier) {
  if (UseCompressedOops) {
    if (prebarrier) {
      update_barrier_set_pre((narrowOop*)dest, exchange_value);
    }
    // encode exchange and compare value from oop to T
    narrowOop val = encode_heap_oop(exchange_value);
    narrowOop cmp = encode_heap_oop(compare_value);

    narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);//核心
    // decode old from T to oop
    return decode_heap_oop(old);
  } else {
    if (prebarrier) {
      update_barrier_set_pre((oop*)dest, exchange_value);
    }
    return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);//核心
  }
}

    如上的List-3所示,核心的CAS调用Atomic::cmpxchg(val, (narrowOop*)dest, cmp)和Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value)。

    cmpxchg的实现是在http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/runtime/atomic.cpp中,如下List-4所示

List-4

jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
  assert(sizeof(jbyte) == 1, "assumption.");
  uintptr_t dest_addr = (uintptr_t)dest;
  uintptr_t offset = dest_addr % sizeof(jint);
  volatile jint* dest_int = (volatile jint*)(dest_addr - offset);
  jint cur = *dest_int;//对象当前值
  jbyte* cur_as_bytes = (jbyte*)(&cur);
  jint new_val = cur;
  jbyte* new_val_as_bytes = (jbyte*)(&new_val);
  new_val_as_bytes[offset] = exchange_value;
  //这里有个for循环,资料上说“ 比较当前值与期望值,如果相同则更新,不同则直接返回”?
  while (cur_as_bytes[offset] == compare_value) {
    jint res = cmpxchg(new_val, dest_int, cur);
    if (res == cur) break;
    cur = res;
    new_val = cur;
    new_val_as_bytes[offset] = exchange_value;
  }
  return cur_as_bytes[offset];
}

    cmpxchg_ptr的实现由不同的系统而实现不同,以64位linux为例,是在http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • HttpSession之学习笔记 原

    在HTTP/1.1中,在步骤3执行完成后,connection不再被关闭,在connection有效的前提细,后面client不再需要执行步骤1,直接执行步骤2...

    克虏伯
  • Springsecurity-oauth2之ClientDetailsService

        ClientDetailsService的实现类有InMemoryClientDetailsService和JdbcClientDetailsServi...

    克虏伯
  • nginx中取消对js|css等的缓存 原

        我们只要修改下nginx中的.conf文件就可以了,如下List-1所示。如何部署静态资源文件见我的这篇博客。

    克虏伯
  • Intellij 显示树连接线

    HoneyMoose
  • Linux下搜狗输入法和快捷键Ctrl+Space冲突的解决

    把搜狗的启动快捷键给删了(如果有两个键盘【英+中】,你按Shift就可以切换了,完全没必要占着茅坑)

    逸鹏
  • 表观转录组学-m6A简介

    DNA甲基化作为重要的表观遗传学标记,研究的非常广泛。与DNA相对应,在RNA水平也存在着多种化学修饰,已经发现的就有100种以上,在编码和非编码RNA上都存在...

    生信修炼手册
  • SEO优化之百度主动推送链接

    本节来说下seo里面的链接问题,为了让我们最近更新的文章尽快被百度收录,以前都是人为的去百度搜索引擎上面提交链接,让蜘蛛过来抓取,后期百度也出了一个接口(暂叫它...

    小白程序猿
  • 文字处理控件功能比较:TX Text Control vs. RichTextBox

    任何机构都需要创建和编辑文档,因此在机构的信息化系统中都需要文档的创建、编辑、转换等功能。通常情况下,我们可以使用VisualStudio自带的RichText...

    葡萄城控件
  • 从零开始一起学习SLAM | 不推公式,如何真正理解对极约束?

    版权声明:本文为博主原创文章,未经博主允许不得转载。违者必究。 https://blog.c...

    用户1150922
  • JS和TS中的void[每日前端夜话0xBE]

    void 作为运算符存在于 JavaScript 中,而作为基本类型存在于 TypeScript 中。在这两个世界中,void 的工作机制与大多数人习惯的有点不...

    疯狂的技术宅

扫码关注云+社区

领取腾讯云代金券