sun.misc.Unsafe中一些常用方法记录
sun.misc.Unsafe中一些常用方法记录
前情摘要
sun公司提供了可以用于直接操作内存的类,这个类就是sun.misc.Unsafe。因为Java本身是不会涉及到直接操作内存的,Java API也没有提供这些操作,内存管理全部交给虚拟机来做。Sun之所以提供这个类,因为有些功能现有的Java API满足不了,如果没有这个类,可能就没有现在原子类,J.U.C包了,也许也没了各种Concurrent Collection类,可能也没了NIO的堆外内存,所以这个类十分的有用,并且很重要,Sun也没有开放这个类的源代码,并且对它的使用也做了一些限制。
通过反编译看到这个类中,几乎所有的方法都是native修饰的,即使其他非native修饰的,最后也是在调用本类的其他native方法。
Unsafe提供了一个static修饰的静态方法,用来获取这个类的实例,这是一个单例。
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
这个getUnsafe()方法并不是直接返回Unsafe的实例,而是做了校验。通过校验直接使用getUnsafe这个方法的类的类加载器是否为Bootstrap类加载器,来做安全检查。由于Java API中的类都是由Bootstrap类加载器加载的,所以是可以直接调用这个方法来获取Unsafe的实例。不过如果要在自己的代码中使用Unsafe,则需要通过反射修改theUnsafe字段的访问修饰符,然后获取Unsafe的实例。由于Unsafe可以直接操作内存,所以存在很大的风险,使用时需要特别谨慎!
想阅读下关于原子类和J.U.C包下的一些实现,发现这些经常使用的方法,记录下每个方法的具体含义,不然没法理解整个客户端方法的行为。
整个Unsafe类中共分为以下几类操作:
- 底层内存信息相关的 比如内存页大小
- 操作对象及其字段 如:实例化对象,获取实例域的偏移量
- 操作类以及静态字段 如:定义一个类,获取静态字段的偏移量
- 操作数据对象
- 同步操作 提供操作监控器和CAS的支持
- 内存操作 主要是内存的分配,复制,销毁等 NIO中用到的多
JUC和原子类以及并发集合中主要用到以下这些方法
Unsafe.putObject()
将一个引用类型的值存入到给定对象的变量中,这个方法的参数列表为putObject(Object o, long offset, Object x),这里就是将对象x的引用,存到对象o的偏移量为offset的变量上。要注意这个操作不保证内存可见性,也就是说对对象o的指定字段的更新,并不会在多线程环境下被其他线程发现值的变动。所以提供了一个具有volatile语义的方法putObjectVolatile(),这个操作具有volatile语义的store语义,并不具备load的语义,如果想在获取时具备load的语义,可以使用getObjectVolatile()。
Unsafe.park()
此方法主要用于阻塞当前线程,方法的参数为park(boolean absolute, long time),如果absolute为false,time为0,则表示一直阻塞,直至unpark方法被调用,或者被中断。如果absolute为false,time不为0,则表示为给定的纳秒过后,中断阻塞,相应的线程可以被系统调度。如果absolute为true,time的单位为毫秒,不过这是一个绝对时间,Epoch Time—— Unix纪元时间 1970.1.1 零时,absolute表示的绝对是指基于这个时间的绝对时间,也就是说park(true, System.currentTimeMillis()+N)这种写法才是对的,不然输入的任意数字都没有作用的,不会起到阻塞线程的效果。
会将线程一直阻塞,直至以下情况发生:
- 当相应的unpark方法在park方法调用前被调用,park方法调用会被立即返回
- 当相应的unpark方法在park方法后被调用,park方法返回
- 在调用park方法的前后,如果检测到线程已经被设置为中断,则park方法立即返回
- absolute为false并且time不为0,所给的纳秒已经过了
- absolute为true,并且所给的时间(必须是在Epoch纪元时间的基础上,通常取当前距离纪元时间的毫秒数加上希望阻塞时间毫秒数)毫秒已经用完
- 无理由返回
Unsafe.unpark()
将指定的线程从park阻塞状态中恢复过来,方法仅有一个参数unpark(Thraed thread),要确保thread对象没有被销毁,也就是要检查不为null
Unsafe.getObjectVolatile()
获取所给对象的所给变量的值,使用volatile语义的load语义,会在实际获取这个值的时候从主存中加载,不会使用CPU缓存中的,总能确保获取到的是有效的值。 getObjectVolatile(Object o, long offset)
Unsafe.getInt()
有三个重载方法getInt(Object o, long offset)、getInt(long address) 和getIntVolatile(long address),都是从指定的位置获取变量的值,只不过第一个的offset是相对于对象o的相对偏移量,第二个address是绝对地址偏移量。如果第一个方法中o为null是,offset也会被作为绝对偏移量。第三个则是带有volatile语义的load读操作。
Unsafe.putInt()
同样有三个在用的重载方法,参数也差不多同putInt类似,含义则是相反,用于对指定内存地址的变量赋值。
putInt(Object o, long offset, int x)、putInt(long address) 和putIntVolatile(Object o, long offset, int x),最后一个是Volatile版本的putInt方法。
Unsafe.objectFieldOffset()
这个方法的作用是用来获取指定对象的域的偏移量,这个是指这个字段在内存中的位置相对于这个对象在内存中的起始地址的偏移量,也就是隔了多远,有了这个值,后续就能直接定位到这个域的内存地址,然后获取其中的值去操作。注意,这个方法只适用于域为非static修饰的,static修饰的域需要使用Unsafe.staticFieldOffset()
Usage:
long offset = unsafe.objectFieldOffset(Field var) 方法结收一个java.lang.reflect.Field对象。
静态域的偏移量也是一样的使用,方法名不同。
Unsafe.compareAndSwapObject()
以CAS的方式来更新一个引用类型的字段值,如果更新成功则返回true,否则返回false。
Usage:
boolean casResult = unsafe.compareAndSwapObject(object,offset,expected,update);
这个方法本身不会有自旋行为,直接做CAS操作,如果失败立即返回。通常是我们在代码中通过无限循环实现CAS的自旋,并且需要被更新的域一般都是用volatile修饰的,不然多线程环境下无法保证正确性。
如果想通过此方式来CAS操作静态域的值,第一个参数为静态域所在的Class对象。
Unsafe.compareAndSwapInt()
和上面的方法作用一样,只不过是用来操作int类型的变量
Unsafe.putOrderedInt()
Unsafe.putIntVolatile()的有序版本/延迟版本,只保证最终将制定的变量更新为新的值。
Unsafe.getAndSetInt()
这个不属于native方法,是用getIntVolatile 和compareAndSwapInt两个方法组合,对指定的变量设置为新的值,不过会返回设置新值前的旧值,而不是无条件直接设置,在竞争的条件下,这样就需要在循环中不断做CAS。
Unsafe.getAndAddInt()
这个同样不属于native方法,和上面差不多,只不过是在旧值的基础上做了个加新值的操作
sun.misc.Unsafe中一些常用方法记录的更多相关文章
- JDK 1.8 sun.misc.Unsafe类CAS底层实现
在java.util.concurrent包下面的很多类为了追求性能都采用了sun.misc.Unsafe类中的CAS操作,从而避免使用synchronized等加锁方式带来性能上的不足. 在sun. ...
- Java中的sun.misc.Unsafe包
chronicle项目:https://github.com/peter-lawrey/Java-Chronicle 这个项目是利用mmap机制来实现高效的读写数据,号称每秒写入5到20百万条数据. ...
- Java sun.misc.Unsafe类的学习笔记
Java未开源的Unsafe类 Unsafe类可以为我们提供高效并且线程安全方式操作变量,直接和内存数据打交道. 获取Unsafe实体的方法 private static Unsafe getUnsa ...
- 一文了解sun.misc.Unsafe
Java语言和JVM平台已经度过了20岁的生日.它最初起源于机顶盒.移动设备和Java-Card,同时也应用在了各种服务器系统中,Java已成为物联网(Internet of Things)的通用语言 ...
- 并发编程之sun.misc.Unsafe类
1.Unsafe知识点整理 2.代码: package com.javabasic.unsafe; import java.lang.reflect.Field; import sun.misc.Un ...
- sun.misc.Unsafe的理解
以下sun.misc.Unsafe源码和demo基于jdk1.7: 最近在看J.U.C里的源码,很多都用到了sun.misc.Unsafe这个类,一知半解,看起来总感觉有点不尽兴,所以打算对Unsaf ...
- java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值
在上一篇文章中.我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下.如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证 ...
- sun.misc.Unsafe 详解
原文地址 译者:许巧辉 校对:梁海舰 Java是一门安全的编程语言,防止程序员犯很多愚蠢的错误,它们大部分是基于内存管理的.但是,有一种方式可以有意的执行一些不安全.容易犯错的操作,那就是使用Unsa ...
- Java sun.misc.unsafe类
Java是一个安全的开发工具,它阻止开发人员犯很多低级的错误,而大部份的错误都是基于内存管理方面的.如果你想搞破坏,可以使用Unsafe这个类.这个类是属于sun.*API中的类,并且它不是J2SE中 ...
随机推荐
- vue的param和query两种传参方式及URL的显示
路由配置: // 首页 { path: '/home', name:'home', component:Home }, // 行情 { path: '/markets', name:'market', ...
- 双射 - hash去重
题目描述Two undirected simple graphs and where are isomorphic when there exists a bijection on V satisfy ...
- 华为,小米部分机型微信浏览器rem不适配的解决方案
针对近日华为,小米的部分机型,在升级系统或升级微信之后,微信内置浏览器产生的rem不能正确填充满的问题,有如下解决方案 目前来看,产生这个情况的原因是因为给html附font-size时,附上的fon ...
- java中implements和extends的区别
1,extends是继承某个类的,可以使用某个类的方法,也可以重写父类的方法. 2,implements是用于实现类接口,可以实现一个或多个类的接口,接口的方法一般为空的,所以必须重写这一个或多个的方 ...
- php变量中两种特殊类型
第一种----资源 资源(resource):资源是由专门的函数来建立和使用的,例如打开文件.数据连接.图形画布.我们可以对资源进行操作(创建.使用和释放).任何资源,在不需要的时候应该被及时释放.如 ...
- 机器学习-TensorFlow建模过程 Linear Regression线性拟合应用
TensorFlow是咱们机器学习领域非常常用的一个组件,它在数据处理,模型建立,模型验证等等关于机器学习方面的领域都有很好的表现,前面的一节我已经简单介绍了一下TensorFlow里面基础的数据结构 ...
- Excel.Application使用手册
Excel.Application组件使用方法,适合应用于使用EXCEL组件做WEB应用开发. 转自http://bbs.xtjc.com/thread-376095-1-1.html 定制模块行为( ...
- 用JAVA分别实现WebSocket客户端与服务端
最近公司在搞一个项目刚好需要用到WebSocket技术来实现实时数据的传输,因为之前也没接触过,所以捣鼓了好些天,最近恰巧有空就写写.有误的地方还请大牛们能及时指正. 项目背景:基于spring+sp ...
- linux容器技术之chroot
linux容器技术之chroot linux chroot 机制的由来 root 用户启动一个daemon,必须用root 用户来启动,比如一个web 服务器(nginx/apapce 80端口)是在 ...
- Docker底层架构之基础架构
Docker 采用了 C/S架构,包括客户端和服务端. Docker daemon 作为服务端接受来自客户 的请求,并处理这些请求(创建.运行.分发容器). 客户端和服务端既可以运行在一个机器上,也可 ...