一篇看懂Java中的Unsafe类
前言
本文主要给大家介绍了关于java中unsafe类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧
1.unsafe类介绍
unsafe类是在sun.misc包下,不属于java标准。但是很多java的基础类库,包括一些被广泛使用的高性能开发库都是基于unsafe类开发的,比如netty、hadoop、kafka等。
使用unsafe可用来直接访问系统内存资源并进行自主管理,unsafe类在提升java运行效率,增强java语言底层操作能力方面起了很大的作用。
unsafe可认为是java中留下的后门,提供了一些低层次操作,如直接内存访问、线程调度等。
官方并不建议使用unsafe。
下面是使用unsafe的一些例子。
1.1实例化私有类
import java.lang.reflect.field; import sun.misc.unsafe; public class unsafeplayer { public static void main(string[] args) throws exception { //通过反射实例化unsafe field f = unsafe.class.getdeclaredfield("theunsafe"); f.setaccessible(true); unsafe unsafe = (unsafe) f.get(null); //实例化player player player = (player) unsafe.allocateinstance(player.class); player.setname("li lei"); system.out.println(player.getname()); } } class player{ private string name; private player(){} public string getname() { return name; } public void setname(string name) { this.name = name; } }
1.2cas操作,通过内存偏移地址修改变量值
java并发包中的synchronousqueue中的transferstack中使用cas更新栈顶。
/ unsafe mechanics private static final sun.misc.unsafe unsafe; private static final long headoffset; static { try { unsafe = sun.misc.unsafe.getunsafe(); class<?> k = transferstack.class; headoffset = unsafe.objectfieldoffset (k.getdeclaredfield("head")); } catch (exception e) { throw new error(e); } } //栈顶 volatile snode head; //更新栈顶 boolean cashead(snode h, snode nh) { return h == head && unsafe.compareandswapobject(this, headoffset, h, nh); }
1.3直接内存访问
unsafe的直接内存访问:用unsafe开辟的内存空间不占用heap空间,当然也不具有自动内存回收功能。做到像c一样*利用系统内存资源。
2.unsafe类源码分析
unsafe的大部分api都是native的方法,主要包括以下几类:
1)class相关。主要提供class和它的静态字段的操作方法。
2)object相关。主要提供object和它的字段的操作方法。
3)arrray相关。主要提供数组及其中元素的操作方法。
4)并发相关。主要提供低级别同步原语,如cas、线程调度、volatile、内存屏障等。
5)memory相关。提供了直接内存访问方法(绕过java堆直接操作本地内存),可做到像c一样*利用系统内存资源。
6)系统相关。主要返回某些低级别的内存信息,如地址大小、内存页大小。
2.1class相关
//静态属性的偏移量,用于在对应的class对象中读写静态属性 public native long staticfieldoffset(field f); public native object staticfieldbase(field f); //判断是否需要初始化一个类 public native boolean shouldbeinitialized(class<?> c); //确保类被初始化 public native void ensureclassinitialized(class<?> c); //定义一个类,可用于动态创建类 public native class<?> defineclass(string name, byte[] b, int off, int len, classloader loader, protectiondomain protectiondomain); //定义一个匿名类,可用于动态创建类 public native class<?> defineanonymousclass(class<?> hostclass, byte[] data, object[] cppatches);
2.2object相关
java中的基本类型(boolean、byte、char、short、int、long、float、double)及对象引用类型都有以下方法。
//获得对象的字段偏移量 public native long objectfieldoffset(field f); //获得给定对象地址偏移量的int值 public native int getint(object o, long offset); //设置给定对象地址偏移量的int值 public native void putint(object o, long offset, int x);
//创建对象,但并不会调用其构造方法。如果类未被初始化,将初始化类。 public native object allocateinstance(class<?> cls) throws instantiationexception;
2.3数组相关
/** * report the offset of the first element in the storage allocation of a * given array class. if {@link #arrayindexscale} returns a non-zero value * for the same class, you may use that scale factor, together with this * base offset, to form new offsets to access elements of arrays of the * given class. * * @see #getint(object, long) * @see #putint(object, long, int) */ //返回数组中第一个元素的偏移地址 public native int arraybaseoffset(class<?> arrayclass); //boolean、byte、short、char、int、long、float、double,及对象类型均有以下方法 /** the value of {@code arraybaseoffset(boolean[].class)} */ public static final int array_boolean_base_offset = theunsafe.arraybaseoffset(boolean[].class); /** * report the scale factor for addressing elements in the storage * allocation of a given array class. however, arrays of "narrow" types * will generally not work properly with accessors like {@link * #getbyte(object, int)}, so the scale factor for such classes is reported * as zero. * * @see #arraybaseoffset * @see #getint(object, long) * @see #putint(object, long, int) */ //返回数组中每一个元素占用的大小 public native int arrayindexscale(class<?> arrayclass); //boolean、byte、short、char、int、long、float、double,及对象类型均有以下方法 /** the value of {@code arrayindexscale(boolean[].class)} */ public static final int array_boolean_index_scale = theunsafe.arrayindexscale(boolean[].class);
通过arraybaseoffset和arrayindexscale可定位数组中每个元素在内存中的位置。
2.4并发相关
2.4.1cas相关
cas:compareandswap,内存偏移地址offset,预期值expected,新值x。如果变量在当前时刻的值和预期值expected相等,尝试将变量的值更新为x。如果更新成功,返回true;否则,返回false。
//更新变量值为x,如果当前值为expected //o:对象 offset:偏移量 expected:期望值 x:新值 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);
从java 8开始,unsafe中提供了以下方法:
//增加 public final int getandaddint(object o, long offset, int delta) { int v; do { v = getintvolatile(o, offset); } while (!compareandswapint(o, offset, v, v + delta)); return v; } public final long getandaddlong(object o, long offset, long delta) { long v; do { v = getlongvolatile(o, offset); } while (!compareandswaplong(o, offset, v, v + delta)); return v; } //设置 public final int getandsetint(object o, long offset, int newvalue) { int v; do { v = getintvolatile(o, offset); } while (!compareandswapint(o, offset, v, newvalue)); return v; } public final long getandsetlong(object o, long offset, long newvalue) { long v; do { v = getlongvolatile(o, offset); } while (!compareandswaplong(o, offset, v, newvalue)); return v; } public final object getandsetobject(object o, long offset, object newvalue) { object v; do { v = getobjectvolatile(o, offset); } while (!compareandswapobject(o, offset, v, newvalue)); return v;
2.4.2线程调度相关
//取消阻塞线程 public native void unpark(object thread); //阻塞线程 public native void park(boolean isabsolute, long time); //获得对象锁 public native void monitorenter(object o); //释放对象锁 public native void monitorexit(object o); //尝试获取对象锁,返回true或false表示是否获取成功 public native boolean trymonitorenter(object o);
2.4.3volatile相关读写
java中的基本类型(boolean、byte、char、short、int、long、float、double)及对象引用类型都有以下方法。
//从对象的指定偏移量处获取变量的引用,使用volatile的加载语义 //相当于getobject(object, long)的volatile版本 public native object getobjectvolatile(object o, long offset); //存储变量的引用到对象的指定的偏移量处,使用volatile的存储语义 //相当于putobject(object, long, object)的volatile版本 public native void putobjectvolatile(object o, long offset, object x);
/** * version of {@link #putobjectvolatile(object, long, object)} * that does not guarantee immediate visibility of the store to * other threads. this method is generally only useful if the * underlying field is a java volatile (or if an array cell, one * that is otherwise only accessed using volatile accesses). */ public native void putorderedobject(object o, long offset, object x); /** ordered/lazy version of {@link #putintvolatile(object, long, int)} */ public native void putorderedint(object o, long offset, int x); /** ordered/lazy version of {@link #putlongvolatile(object, long, long)} */ public native void putorderedlong(object o, long offset, long x);
2.4.4内存屏障相关
java 8引入 ,用于定义内存屏障,避免代码重排序。
//内存屏障,禁止load操作重排序,即屏障前的load操作不能被重排序到屏障后,屏障后的load操作不能被重排序到屏障前 public native void loadfence(); //内存屏障,禁止store操作重排序,即屏障前的store操作不能被重排序到屏障后,屏障后的store操作不能被重排序到屏障前 public native void storefence(); //内存屏障,禁止load、store操作重排序 public native void fullfence();
2.5直接内存访问(非堆内存)
allocatememory所分配的内存需要手动free(不被gc回收)
//(boolean、byte、char、short、int、long、float、double)都有以下get、put两个方法。 //获得给定地址上的int值 public native int getint(long address); //设置给定地址上的int值 public native void putint(long address, int x); //获得本地指针 public native long getaddress(long address); //存储本地指针到给定的内存地址 public native void putaddress(long address, long x); //分配内存 public native long allocatememory(long bytes); //重新分配内存 public native long reallocatememory(long address, long bytes); //初始化内存内容 public native void setmemory(object o, long offset, long bytes, byte value); //初始化内存内容 public void setmemory(long address, long bytes, byte value) { setmemory(null, address, bytes, value); } //内存内容拷贝 public native void copymemory(object srcbase, long srcoffset, object destbase, long destoffset, long bytes); //内存内容拷贝 public void copymemory(long srcaddress, long destaddress, long bytes) { copymemory(null, srcaddress, null, destaddress, bytes); } //释放内存 public native void freememory(long address);
2.6系统相关
//返回指针的大小。返回值为4或8。 public native int addresssize(); /** the value of {@code addresssize()} */ public static final int address_size = theunsafe.addresssize(); //内存页的大小。 public native int pagesize();
3.参考资料
说一说java中的unsafe类
java魔法类:sun.misc.unsafe
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
推荐阅读
-
一篇看懂Java中的Unsafe类
-
java中Object类的equals理解
-
Java日期时间API系列10-----Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter
-
定义两个接口,其中各包括一个抽象方法分别用来完成两个数的加法和减法操作,然后创建一个类KY6_3来实现这两个接口中的抽象方法。编写程序KY6_3.java,将源程序写在实验报告中。
-
JAVA 将一个StringBuffer类对象中的所有小写字母变为大写字母,大写字母变为小写字母,然后输出显示
-
荐 Java——集合中的Map接口通过HashMap类实现一些常用的方法
-
Java中的File类
-
【Java】利用json工具类,传入字段名,获取集合中的对象属性值集合
-
Java中接口和抽象类的区别?
-
一篇文章看懂JavaScript中的回调