前言

Unsafe 是位于 sun.misc 包下的一个类。Unsafe 提供的 API 大致可分为内存操作、CAS、Class 相关、对象操作、线程调度、系统信息获取、内存屏障、数组操作等几类。由于并发相关的源码很多用到了 CAS,比如 java.util.concurrent.atomic 相关类、AQS、CurrentHashMap 等相关类。所以本文主要讲 Unsafe 中 CAS 的实现。笔者源码环境为 OpenJDK8

CAS 相关

主要相关源码

    /**
* 参数说明
* @param o 包含要修改field的对象
* @param offset 对象中某个参数field的偏移量,该偏移量不会改变
* @param expected 期望该偏移量对应的field值
* @param x 更新值
* @return true|false
*/
public final native boolean compareAndSwapObject(Object o, long offset,
Object expected,
Object x); public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x); public final native boolean compareAndSwapLong(Object o, long offset,
long expected,
long x);

CAS 是实现并发算法时常用到的一种技术。CAS 操作包含三个操作数——内存位置、预期原值及新值。执行 CAS 操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。我们都知道,CAS 是一条 CPU 的 原子指令(cmpxchg 指令),不会造成所谓的数据不一致问题,Unsafe 提供的 CAS 方法(如 compareAndSwapXXX)底层实现即为 CPU 指令 cmpxchg。

说明:对象的基地址 baseAddress+valueOffset 得到 value 的内存地址 valueAddress

Unsafe 类获取

首先看下 Unsafe 的单例实现

    private static final Unsafe theUnsafe = new Unsafe();
// 注解表明需要引导类加载器
@CallerSensitive
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
// 仅在引导类加载器`BootstrapClassLoader`加载时才合法
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}

那如若想使用这个类,该如何获取其实例?有如下两个可行方案。

其一,从 getUnsafe 方法的使用限制条件出发,通过 Java 命令行命令 -Xbootclasspath/a 把调用 Unsafe 相关方法的类 A 所在 jar 包路径追加到默认的 bootstrap 路径中,使得 A 被引导类加载器加载,从而通过 Unsafe.getUnsafe 方法安全的获取 Unsafe 实例。

java -Xbootclasspath/a: ${path}   // 其中path为调用Unsafe相关方法的类所在jar包路径

其二,通过反射获取单例对象 theUnsafe。

@Slf4j
public class UnsafeTest { private static Unsafe reflectGetUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
} public static void main(String[] args) {
Unsafe unsafe = UnsafeTest.reflectGetUnsafe();
}
}

CAS 演练

  1. 创建一个类
@Getter@Setter
public class User {
private String name;
private int age;
}
  1. 反射获取 Unsafe 并测试 CAS
@Slf4j
public class UnsafeTest { private static Unsafe reflectGetUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
} public static void main(String[] args) throws Exception{
Unsafe unsafe = UnsafeTest.reflectGetUnsafe();
// allocateInstance: 对象操作。绕过构造方法、初始化代码来创建对象
User user = (User)unsafe.allocateInstance(User.class);
user.setName("admin");
user.setAge(17); Field name = User.class.getDeclaredField("name");
Field age = User.class.getDeclaredField("age"); // objectFieldOffset: 返回对象成员属性在内存地址相对于此对象的内存地址的偏移量
long nameOffset = unsafe.objectFieldOffset(name);
long ageOffset = unsafe.objectFieldOffset(age); System.out.println("name内存偏移地址:" + nameOffset);
System.out.println("age 内存偏移地址:" + ageOffset); System.out.println("---------------------"); // CAS操作
int currentValue = unsafe.getIntVolatile(user, ageOffset);
System.out.println("age内存当前值:" + currentValue);
boolean casAge = unsafe.compareAndSwapInt(user, ageOffset, 17, 18);
System.out.println("age进行CAS更新成功:" + casAge);
System.out.println("age更新后的值:" + user.getAge()); System.out.println("---------------------"); // volatile修饰,保证可见性、有序性
unsafe.putObjectVolatile(user, nameOffset, "test");
System.out.println("name更新后的值:" + unsafe.getObjectVolatile(user, nameOffset)); }
}

结果输出

name内存偏移地址:16
age 内存偏移地址:12
---------------------
age内存当前值:17
age进行CAS更新成功:true
age更新后的值:18
---------------------
name更新后的值:test

Unsafe 中 CAS 操作是原子性的,所以在秒杀、库存扣减中也可以使用 Unsafe 来扣减库存。

结语

本文对 Java 中的 sun.misc.Unsafe 的用法及应用场景进行了基本介绍,仅做后续源码阅读的铺垫。到此,本篇文章就写完了,感谢大家的阅读!如果您觉得对您有帮助,请关注公众号【当我遇上你】。

Unsafe中CAS的实现的更多相关文章

  1. JDK 1.8 sun.misc.Unsafe类CAS底层实现

    在java.util.concurrent包下面的很多类为了追求性能都采用了sun.misc.Unsafe类中的CAS操作,从而避免使用synchronized等加锁方式带来性能上的不足. 在sun. ...

  2. java8中CAS的增强

    注:ifeve.com的同名文章为本人所发,此文在其基础做了些调整.转载请注明出处! 一.java8中CAS的增强 前些天,我偶然地将之前写的用来测试AtomicInteger和synchronize ...

  3. Unsafe与CAS

    Unsafe 简单讲一下这个类.Java无法直接访问底层操作系统,而是通过本地(native)方法来访问.不过尽管如此,JVM还是开了一个后门,JDK中有一个类Unsafe,它提供了硬件级别的原子操作 ...

  4. Java 8 中 CAS 的增强

    几天前,我偶然地将之前写的用来测试AtomicInteger和synchronized的自增性能的代码跑了一下,意外地发现AtomicInteger的性能比synchronized更好了,经过一番原因 ...

  5. Java原子类中CAS的底层实现

    Java原子类中CAS的底层实现 从Java到c++到汇编, 深入讲解cas的底层原理. 介绍原理前, 先来一个Demo 以AtomicBoolean类为例.先来一个调用cas的demo. 主线程在f ...

  6. 1. AtomicInteger 、Unsafe 及 CAS方法的整理

    本文摘自: https://blog.csdn.net/fanrenxiang/article/details/80623884 http://ifeve.com/sun-misc-unsafe/ h ...

  7. sun.misc.Unsafe中一些常用方法记录

    sun.misc.Unsafe中一些常用方法记录 前情摘要 sun公司提供了可以用于直接操作内存的类,这个类就是sun.misc.Unsafe.因为Java本身是不会涉及到直接操作内存的,Java A ...

  8. AbstractQueuedSynchronizer中CAS的疑惑

    这段代码是AQS框架中将当前节点入队的操作. Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail ...

  9. AutomaticInteger中CAS运用分析

    摘要 在接触CAS的时候虽然对它流程了解了但是对其如何解决并发问题还是一直有疑问的,所以在就选择了java中典型线程安全的AtomicInteger类进行了源码的分析. CAS简介 CAS的全称为co ...

随机推荐

  1. python后端面试第四部分:django框架--长期维护

    1 列举Http请求中常见的请求方式  https://www.cnblogs.com/andy0816/p/12360866.html2 谈谈你对HTTP协议的认识.1.1 长连接  https:/ ...

  2. differences between evolution

  3. Python之循环条件、变量、字符串格式化

    一.认识python python语言的优缺点,自行百度,这里不概述,简单说下,python是一门面向对象,解释型计算机语言.那么问题来了,解释型和编译型语言有什么区别? 1.解释型和编译型语言区别 ...

  4. Java IO: 序列化与ObjectInputStream、ObjectOutputStream

    作者:Jakob Jenkov  译者: 李璟(jlee381344197@gmail.com) 本小节会简要概括Java IO中的序列化以及涉及到的流,主要包括ObjectInputStream和O ...

  5. FPGA大疆考试准备内容

    1.寄存器与锁存器 锁存器:电平触发的存储单元,在有效电平时间里可以多次改变数据. 优点:    占触发器资源少,缺点是容易产生毛刺.(附上去毛刺的方法:格雷码计数器(*https://blog.cs ...

  6. [LC] 211. Add and Search Word - Data structure design

    Design a data structure that supports the following two operations: void addWord(word) bool search(w ...

  7. 化学键|甘氨酸|谷氨酸|半胱胺酸|motif|domain|疏水相互作用|序列相似性|clustering analysis|Chou and Fasman|GOR|PHD|穿线法|first-principle ab initio folding|

    化学键|甘氨酸|谷氨酸|半胱胺酸|motif|domain|疏水相互作用|序列相似性|clustering analysis|Chou and Fasman|GOR|PHD|穿线法|first-pri ...

  8. 浅谈URL重定向

    转载:https://blog.csdn.net/kiyoometal/article/details/90698761 重定向原理 HTTP 协议的重定向响应的状态码为 3xx .浏览器在接收到重定 ...

  9. Tmux 速成教程:技巧和调整

    本文转自:http://blog.jobbole.com/87584/ 简介 有些开发者经常要使用终端控制台工作,导致最终打开了过多的标签页.如果你也是他们当中的一员,或者你正在实践结对编程,那么我推 ...

  10. Sublime Text2 使用心得总结

    sublime text2是开发代码编辑的神器 ,编辑器界面优美,操作速度快速.而且Sublime Text2是一款跨平台的编辑器,再也不用为换平台而找不到合适的.熟悉的编辑器担忧了. Sublime ...