文档章节

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

克虏伯
 克虏伯
发布于 08/21 01:17
字数 612
阅读 7
收藏 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

© 著作权归作者所有

共有 人打赏支持
克虏伯

克虏伯

粉丝 13
博文 270
码字总数 91553
作品 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

没有更多内容

加载失败,请刷新页面

加载更多

00.编译OpenJDK-8u40的整个过程

前言 历经2天的折腾总算把OpenJDK给编译成功了,要说为啥搞这个,还得从面试说起,最近出去面试经常被问到JVM的相关东西,总感觉自己以前学的太浅薄,所以回来就打算深入学习,目标把《深入理...

凌晨一点
今天
2
0
python: 一些关于元组的碎碎念

初始化元组的时候,尤其是元组里面只有一个元素的时候,会出现一些很蛋疼的情况: def checkContentAndType(obj): print(obj) print(type(obj))if __name__=="__main__": tu...

Oh_really
昨天
6
2
jvm crash分析工具

介绍一款非常好用的jvm crash分析工具,当jvm挂掉时,会产生hs_err_pid.log。里面记录了jvm当时的运行状态以及错误信息,但是内容量比较庞大,不好分析。所以我们要借助工具来帮我们。 Cras...

xpbob
昨天
116
0
Qt编写自定义控件属性设计器

以前做.NET开发中,.NET直接就集成了属性设计器,VS不愧是宇宙第一IDE,你能够想到的都给你封装好了,用起来不要太爽!因为项目需要自从全面转Qt开发已经6年有余,在工业控制领域,有一些应用...

飞扬青云
昨天
4
0
我为什么用GO语言来做区块链?

Go语言现在常常被用来做去中心化系统(decentralised system)。其他类型的公司也都把Go用在产品的核心模块中,并且它在网站开发中也占据了一席之地。 我们在决定做Karachain的时候,考量(b...

HiBlock
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部