Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Unsafe 源码分析

Unsafe 源码分析

作者头像
itliusir
发布于 2020-01-31 03:24:59
发布于 2020-01-31 03:24:59
97500
代码可运行
举报
文章被收录于专栏:刘君君刘君君
运行总次数:0
代码可运行

摘要:

  1. 如何获取 Unsafe 实例
  2. 如何利用 Unsafe API 绕开 JVM的控制
  3. CAS 到底是什么
  4. Unsafe 中的线程调度是怎么回事

TOP 带着问题看源码

  1. 如何获取 Unsafe 实例
  2. 如何利用 Unsafe API 绕开 JVM的控制
  3. CAS 到底是什么
  4. Unsafe 中的线程调度是怎么回事

1. 基本介绍

Unsafe 是用于在实质上扩展 Java 语言表达能力、便于在 Java 代码里实现原本要在 C 层实现的核心库功能用的。这些功能包括裸内存的申请、释放、访问,低层硬件的 atomic/volatile 支持,创建未初始化对象等。但由于 Unsafe 类使 Java 语言拥有不应该暴露的骚操作,增加了程序出问题的风险。

1.1 获取 Unsafe 实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UnsafeTest {
  	private static Unsafe unsafe;
    public static void main(String[] args) throws Exception {
        Class c = UnsafeTest.class.getClassLoader().loadClass("sun.misc.Unsafe");
    		Field f = c.getDeclaredField("theUnsafe");
    		f.setAccessible(true);
    		unsafe = (Unsafe)f.get(c);

    		unsafe.xx();
    }
}

回到 TOP 1 可以明白,通过反射获取 unsafe 实例。

2. 功能介绍

3. 数组相关

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 返回数组中第一个元素的偏移地址
public native int arrayBaseOffset(Class<?> var1);
// 返回数组中一个元素占用的大小
public native int arrayIndexScale(Class<?> var1);

通过定位数组第一个元素的偏移地址和每个元素占用的大小。

例如第一个元素偏移地址是16,存的是 int 类型,则可以通过要查询的 index * 4 + 16 来获取到对应的值。

我们可以在 AtomicIntegerArray 中看到这些操作,不过作者巧妙的通过位运算来计算index对应的偏移量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 1. first index 偏移量
private static final int base = unsafe.arrayBaseOffset(int[].class);
// 2. scale = 4;
int scale = unsafe.arrayIndexScale(int[].class);
// 3. 计算 scale 二进制后面有几个0,如scale = 4(0100),shift = 2
shift = 31 - Integer.numberOfLeadingZeros(scale);
// 4. 根据index对scale进行乘法运算获取偏移量 offset,如index = 1,offset = 4(1 << 2) + 16 = 20
offset = index << shift + base;
// 5. 通过 offset 原子的获取对应的值
unsafe.getIntVolatile(array, offset);

4. 内存屏障

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 内存屏障,禁止 load 操作重排序
public native void loadFence();
// 内存屏障,禁止 store 操作重排序
public native void storeFence();
// 内存屏障,禁止 load、store 操作重排序
public native void fullFence();

内存屏障主要是避免 CPU 或者 编译器对代码重排序。

如并发包中 StampedLock 解决因代码重排序校验不准确,采用loadFence()。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public boolean validate(long stamp) {
    U.loadFence();
    return (stamp & SBITS) == (state & SBITS);
}

5. 系统相关

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 获取系统指针的大小, 64 位是8
public native int addressSize();
// 获取内存页大小,2的幂次方,我本机测试是4096
public native int pageSize();

可以根据内存页大小计算分配页数

6. 线程调度

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 取消阻塞
public native void unpark(Object var1);
// 阻塞直到超时或中断等条件
public native void park(boolean var1, long var2);
// 弃用,获取对象锁
public native void monitorEnter(Object var1);
// 弃用,释放对象锁
public native void monitorExit(Object var1);
// 弃用,尝试获取对象锁
public native boolean tryMonitorEnter(Object var1);

大名鼎鼎的 AQS 就是通过 park、unpark 来对线程阻塞和唤醒的

回到 TOP 4 可以明白其实就是 park unpark

7. 内存操作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 内存分配,相当于c++的os::malloc
public native long allocateMemory(long var1);
// 扩容内存
public native long reallocateMemory(long var1, long var3);
// 给定的内存块中设置值
public native void setMemory(Object var1, long var2, long var4, byte var6);
// 内存拷贝
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 释放内存,相当于c++的os::free
public native void freeMemory(long var1);
// 获取给定地址的XX类型的值
public native byte getXx(long var1);
// 为给定地址设置XX类型的值
public native void putXx(long var1, xx var3);

以上的内存操作针对的都是堆外内存操作,与我们平时自己创建的对象都在堆内不同,堆外不会受到 JVM 内存管理,合理使用可以减少原本堆内内存使 GC 时间减少。

java.nio.DirectByteBuffer 中利用了堆外内存减少堆内堆外的copy

回到 TOP 2 可以明白使用堆外内存操作可以绕开 JVM 控制

8. CAS(Compare And Swap, 比较和替换)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 根据第二个参数”偏移量”去拿偏移量这么多的属性的值和第三个参数对比,如果相同则将该属性值替换为第四个参数。该偏移量是指某个字段相对Java对象的起始位置的偏移量,可以通过unsafe.objectFieldOffset(param)去获取对应属性的偏移量。
public final native boolean compareAndSwapXx(Object var1, long var2, Xx var4, Xx var5);

CAS 是一条 CPU 的原子指令(cmpxchg),如果是多核处理器会加上 LOCK 前缀

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  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;
}

CAS 在并发包中被广泛应用,回到 TOP 3 可以明白 CAS 是一条 CPU 的原子指令。

9. Class 相关

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 获取静态字段的内存地址偏移量
public native long staticFieldOffset(Field var1);
// 获取一个静态类中给定字段的对象指针
public native Object staticFieldBase(Field var1);
// 判断是否需要初始化一个类,因为有可能类还没初始化却去获取静态属性
public native boolean shouldBeInitialized(Class<?> var1);
// 检测类是否已经初始化 
public native void ensureClassInitialized(Class<?> var1);
// 定义一个类
public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);
// 定义一个匿名类
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);

10. 对象操作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 返回对象某个属性相对对象内存地址的偏移量
public native long objectFieldOffset(Field var1);
// 从对象的指定偏移量处获取变量的引用,使用volatile的加载语义
public native Object getObjectVolatile(Object o, long offset);
// 存储变量的引用到对象的指定的偏移量处,使用volatile的存储语义
public native void putObjectVolatile(Object o, long offset, Object x);
// 有序、延迟版本的putObjectVolatile方法,不保证值的改变被其他线程立即看到。只有在field被volatile修饰符修饰时有效
public native void putOrderedObject(Object o, long offset, Object x);
// 绕过构造方法、初始化代码来创建对象
public native Object allocateInstance(Class<?> cls) throws InstantiationException;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-04-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jdk1.8 Unsafe类初探
    在看java原子类时里有很多方法都调用了Unsafe类方法,Unsafe类方法在jdk里没找到源码,然后下载open jdk找到了源码,在/src/share/classes/sun/misc 目录下。定义如下:   
用户4415180
2022/06/23
7210
JUC之Unsafe类
Java 不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe 类提供了硬件级别的原子操作。Unsafe 类使用 private 修饰构造方法,只能使用他自己提供的一个 final 类来进行获取。
小四的技术之旅
2022/07/26
8550
各大框架都在使用的Unsafe类,到底有多神奇?
几乎每个使用 Java开发的工具、软件基础设施、高性能开发库都在底层使用了sun.misc.Unsafe,比如Netty、Cassandra、Hadoop、Kafka等。
程序新视界
2022/05/06
3780
各大框架都在使用的Unsafe类,到底有多神奇?
当面试官问出“Unsafe”类时,我就知道这场面试废了,祖坟都能给你问出来!
依稀记得多年以前的一场面试中,面试官从Java并发编程问到了锁,从锁问到了原子性,从原子性问到了Atomic类库(对着JUC包进行了刨根问底),从Atomic问到了CAS算法,紧接着又有追问到了底层的Unsafe类,当问到Unsafe类时,我就知道这场面试废了,这似乎把祖坟都能给问冒烟啊。
JavaBuild
2024/05/27
1280
当面试官问出“Unsafe”类时,我就知道这场面试废了,祖坟都能给你问出来!
聊聊 Java 中的 Unsafe 类
哈喽,我是狗哥。Unsafe 类位于 rt.jar 包,Unsafe 类提供了硬件级别的原子操作,类中的方法都是 native 方法,它们使用 JNI 的方式访问本地 C++ 实现库。由此提供了一些绕开 JVM 的更底层功能,可以提高程序效率。
JavaFish
2022/01/17
6780
聊聊 Java 中的 Unsafe 类
浅析AtomicLong以及Unsafe
最近关注着限流、降级相关的设计,开源的Hystrix提供了一种设计思路。限流降级的前提是需要了解系统的各种状态,服务的响应情况,接口的调用情况,数据库的情况等等。其中很重要的一个指标就是qps,那么如何统计qps?Hystrix中有个设计非常好的类HystrixRollingNumber,非常适合用来统计qps。HystrixRollingNumber中利用了LongAdder来提高效率,所以本文先会介绍AtomicLong,UnSafe,下篇文章介绍LongAdder,下下篇文章介绍HystrixRollingNumber...
LNAmp
2018/09/05
6170
死磕 java并发包之AtomicInteger源码分析
AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。
彤哥
2019/07/08
5920
并发编程之Atomic&Unsafe魔法类详解
并发编程之Atomic&Unsafe魔法类详解–原子(atom)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为”不可被中断的一个或一系列操作”。在多处理器上实现原子操作就变得有点复杂。本文让我们一起来聊一聊在Inter处理器和Java里是如何实现原子操作的。
一滴水的眼泪
2020/09/21
5150
并发编程之Atomic&Unsafe魔法类详解
java高并发系列 - 第22天:JUC底层工具类Unsafe,高手必须要了解
最近我们一直在学习java高并发,java高并发中主要涉及到类位于java.util.concurrent包中,简称juc,juc中大部分类都是依赖于Unsafe来实现的,主要用到了Unsafe中的CAS、线程挂起、线程恢复等相关功能。所以如果打算深入了解JUC原理的,必须先了解一下Unsafe类。
路人甲Java
2019/12/10
5820
java高并发系列 - 第22天:JUC底层工具类Unsafe,高手必须要了解
AtomicInteger源码分析详解
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
suveng
2019/09/18
6950
AtomicInteger源码分析详解
atomicLong源码分析详解
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
suveng
2019/09/18
5730
atomicLong源码分析详解
Unsafe-java的魔法类-AtomicInteger的原子操作
一般而言,编写底层代码或者影响JVM是很难实现的,当然你可以使用JNI来达到目的,JNI需要和C打交道。
青山师
2023/05/05
1910
Unsafe-java的魔法类-AtomicInteger的原子操作
14.JDK底层Unsafe类是个啥东西?
老王:小陈啊,从今天开始我们就要进入 《结丹篇》 了,在这一篇章里面,要注意听讲啊,对后面的每一个阶段的理解来说都至关重要的......
终有救赎
2023/10/16
2100
14.JDK底层Unsafe类是个啥东西?
【基本功】Java魔法类:Unsafe应用解析
《基本功》专栏又上新了:Java中的Unsafe类在提升运行效率、增强底层资源操作能力方面有很大的用处。但如果在开发过程中使用不当,就会出现各种“莫名其妙”的问题。
美团技术团队
2019/03/22
8260
【基本功】Java魔法类:Unsafe应用解析
并发编程之CAS(Compare and Swap)原理Unsafe类
AQS,非阻塞数据结构和原子变量类(java.util.concurrent.atomic包中的类),这些concurrent包中的基础类都是使用这种模式来实现的,而concurrent包中的高层类又是依赖于这些基础类来实现的。从整体来看,concurrent包的实现示意图如下:
一个会写诗的程序员
2018/08/20
1K0
并发编程之CAS(Compare and Swap)原理Unsafe类
探究CAS原理(基于JAVA8源码分析)define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "define LOCK_IF_MP(mp) _
比较并替换,实现并发算法时常用到的一种技术,在java同步器中大量使用了CAS技术,神奇的实现了多线程执行的安全性 思想很简单:三个参数 一个当前内存值V 旧的预期值A 即将更新的值B 当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。 问题 一个n++的问题。 public class Case { public volatile int n; public void add() { n++; } } 通过java
JavaEdge
2018/05/16
2K0
《探索CAS和Atomic原子操作:并发编程的秘密武器》
CAS(Compare and Swap)和Atomic原子操作是现代并发编程中的关键工具,它们为多线程环境下的数据共享和同步提供了强大的支持。本文将深入剖析CAS和Atomic操作的原理与应用,探讨它们如何在多线程程序中确保数据的一致性和线程安全性。无论您是初学者还是有经验的开发人员,都将从本文中获得有关并发编程的宝贵见解,使您能够更好地利用这些强大的工具来构建高效、可靠的并发应用程序。
杨不易呀
2023/09/27
4980
《探索CAS和Atomic原子操作:并发编程的秘密武器》
重学Java-扒一扒Java并发
先提几个曾经困扰过我的问题啊,看似很简单,而且可能还有很多同学还存在误解,我们来一起看一下。
三好码农
2019/07/02
4620
重学Java-扒一扒Java并发
CAS与自旋锁的实现原理 发布于 20
CAS(Compare And Swap)比较并交换是JUC并发编程中最为重要的一个工具。它在处理并发问题时提供了一个非阻塞的解决方案,引入了一种全新的并发编程思维——乐观锁。这种思想预设所有线程在执行过程中都不会发生冲突,每一个线程都会乐观地认为自己能够成功执行,从而大大降低了线程之间的等待和阻塞,极大地提高了系统的并发性能。
DioxideCN
2023/10/21
5780
Java原子操作Atomic类详解
      1.CAS(Compare And Swap,比较并交换),通常指的是这样一种原子操作:
忧愁的chafry
2022/10/30
7490
Java原子操作Atomic类详解
相关推荐
jdk1.8 Unsafe类初探
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验