文档章节

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

克虏伯
 克虏伯
发布于 08/21 01:17
字数 612
阅读 15
收藏 0

注:这篇文章参考了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

© 著作权归作者所有

共有 人打赏支持
上一篇: Telnet之记录
克虏伯

克虏伯

粉丝 15
博文 318
码字总数 106998
作品 0
渝北
程序员
私信 提问
openJDK之lambda——List的forEach如何实现的

openJDK的版本是openJDK8,如何下载openJDK,请参考我的这篇博客。 这篇内容很简单。 1.List的forEach如何实现 List-1 List的forEach例子 Arrays.asList中底层上是ArrayList,forEach的实现是...

克虏伯
09/17
0
0
Linux下的JDK和OpenJDK有什么具体的区别

大多数Linux发行版本里,内置或者通过软件源安装JDK的话,都是安装的openjdk. openjdk是jdk的开放原始码版本,以GPL协议的形式放出。 openjdk只包含最精简的JDK 在安装openjdk的机器上,输入...

帅帅甩锅
2017/10/29
0
0
centos 安装JAVA 三种方法

由于各Linux开发厂商的不同,因此不同开发厂商的Linux版本操作细节也不一样,今天就来说一下CentOS下JDK的安装: 方法一:手动解压JDK的压缩包,然后设置环境变量 1.在/usr/目录下创建java目录 ...

微笑出品
2017/10/19
0
0
Java 11 将至,不妨了解一下 Oracle JDK 之外的版本

Java 11 计划于本月,即 9 月 25 日发布。与 Java 10 不同,Java 11 不仅提供了长期支持,还将作为 Java 平台的参考实现。新的长期支持版本每三年发布一次,根据后续的发布计划,Java 17 将于...

局长
09/11
0
35
Java 11 将至,除了 Oracle JDK 还有这些版本!

Java 11 计划于本月,即 9 月 25 日发布。与 Java 10 不同,Java 11 不仅提供了长期支持,还将作为 Java 平台的参考实现。新的长期支持版本每三年发布一次,根据后续的发布计划,Java 17 将于...

CSDN资讯
09/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

可自定义扩展底部列表对话框ListBottomSheetDialogFragment

因为需要,为了方便,构建了一个可以自定义扩展的底部列表对话框,可以应付大部分场景。 效果图如下: 1.默认实现: 2.自定义列表实现 3.自定义头部和列表实现 一.可实现功能 1.默认可实现通...

明月春秋
48分钟前
1
0
数据库---增删改查

增:insert into 表名(列名1,列名2) values(‘列值1’,‘列值2’) 多行数据处理:insert into 表名(列名1,列名2) select ‘列值1’,‘列值2’ union select ‘列值1.1’,‘列值2.2...

森林之下
49分钟前
2
0
分布式/集群下session共享方案汇总

除去那些对容器依赖特别高的方案(如: 基于Tomcat的memcached-session-manager / tomcat-redis-session-manager,基于Jetty的jetty-nosql-memcache / jetty-session-redis ),自己整理了下...

哥本哈根的小哥
今天
2
0
Vue中的缩写:v-bind、v-on

v-bind 缩写:: 预期:any (with argument) | Object (without argument) 参数:attrOrProp (optional) 修饰符: .prop - 被用于绑定 DOM 属性。 .camel - (2.1.0+) 将 kebab-case 特性名转换......

文文1
今天
2
0
epoll中使用

1、一个线程epoll_wait时,另一个线程调用epoll_ctl是安全的。 2、使用edge触发,在socket有数据到来后,不收取数据,再次调用epoll_ctl将socket加入,仍会触发下一次动作。 asio用该方法来发...

gelare
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部