简单谈一谈Java中的Unsafe类

  • 更新时间:2022-06-12 17:36:42
  • 编辑:任初珍
给寻找Java相关教程的朋友们精选了Java相关的编程文章,网友养雪娟根据主题投稿了本篇教程内容,涉及到java、unsafe类、ava中的unsafe、java、unsafe相关内容,已被865网友关注,涉猎到的知识点内容可以在下方电子书获得。
透视JAVA:反编译、修补和逆向工程技术
透视JAVA:反编译、修补和逆向工程技术
  • 大小:24.60MB
  • 发布人:辛琛丽
  • 下载:JAVA

Unsafe类是啥?

Java最初被设计为一种安全的受控环境。尽管如此,Java HotSpot还是包含了一个“后门”,提供了一些可以直接操控内存和线程的低层次操作。这个后门类——sun.misc.Unsafe——被JDK广泛用于自己的包中,如java.nio和java.util.concurrent。但是丝毫不建议在生产环境中使用这个后门。因为这个API十分不安全、不轻便、而且不稳定。这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改。有时它可以被用来在不适用C++调试的情况下学习虚拟机内部结构,有时也可以被拿来做性能监控和开发工具。

引言

最近在看Java并发包的源码,发现了神奇的Unsafe类,仔细研究了一下,在这里跟大家分享一下。

简单谈一谈Java中的Unsafe类

Unsafe类是在sun.misc包下,不属于Java标准。但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Cassandra、Hadoop、Kafka等。Unsafe类在提升Java运行效率,增强Java语言底层操作能力方面起了很大的作用。

简单谈一谈Java中的Unsafe类

简单谈一谈Java中的Unsafe类

Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的,官方文档也几乎没有。Oracle正在计划从Java 9中去掉Unsafe类,如果真是如此影响就太大了。

简单谈一谈Java中的Unsafe类

通常我们最好也不要使用Unsafe类,除非有明确的目的,并且也要对它有深入的了解才行。要想使用Unsafe类需要用一些比较tricky的办法。Unsafe类使用了单例模式,需要通过一个静态方法getUnsafe()来获取。但Unsafe类做了限制,如果是普通的调用的话,它会抛出一个SecurityException异常;只有由主类加载器加载的类才能调用这个方法。其源码如下:

public static Unsafe getUnsafe() {
 Class var0 = Reflection.getCallerClass();
 if(!VM.isSystemDomainLoader(var0.getClassLoader())) {
  throw new SecurityException("Unsafe");
 } else {
  return theUnsafe;
 }
}

网上也有一些办法来用主类加载器加载用户代码,比如设置bootclasspath参数。但更简单方法是利用Java反射,方法如下:

 Field f = Unsafe.class.getDeclaredField("theUnsafe");
 f.setAccessible(true);
 Unsafe unsafe = (Unsafe) f.get(null);

获取到Unsafe实例之后,我们就可以为所欲为了。Unsafe类提供了以下这些功能:

一、内存管理。包括分配内存、释放内存等。

该部分包括了allocateMemory(分配内存)、reallocateMemory(重新分配内存)、copyMemory(拷贝内存)、freeMemory(释放内存 )、getAddress(获取内存地址)、addressSize、pageSize、getInt(获取内存地址指向的整数)、getIntVolatile(获取内存地址指向的整数,并支持volatile语义)、putInt(将整数写入指定内存地址)、putIntVolatile(将整数写入指定内存地址,并支持volatile语义)、putOrderedInt(将整数写入指定内存地址、有序或者有延迟的方法)等方法。getXXX和putXXX包含了各种基本类型的操作。

利用copyMemory方法,我们可以实现一个通用的对象拷贝方法,无需再对每一个对象都实现clone方法,当然这通用的方法只能做到对象浅拷贝。

二、非常规的对象实例化。

allocateInstance()方法提供了另一种创建实例的途径。通常我们可以用new或者反射来实例化对象,使用allocateInstance()方法可以直接生成对象实例,且无需调用构造方法和其它初始化方法。

这在对象反序列化的时候会很有用,能够重建和设置final字段,而不需要调用构造方法。

三、操作类、对象、变量。

这部分包括了staticFieldOffset(静态域偏移)、defineClass(定义类)、defineAnonymousClass(定义匿名类)、ensureClassInitialized(确保类初始化)、objectFieldOffset(对象域偏移)等方法。

通过这些方法我们可以获取对象的指针,通过对指针进行偏移,我们不仅可以直接修改指针指向的数据(即使它们是私有的),甚至可以找到JVM已经认定为垃圾、可以进行回收的对象。

四、数组操作。

这部分包括了arrayBaseOffset(获取数组第一个元素的偏移地址)、arrayIndexScale(获取数组中元素的增量地址)等方法。arrayBaseOffset与arrayIndexScale配合起来使用,就可以定位数组中每个元素在内存中的位置。

由于Java的数组最大值为Integer.MAX_VALUE,使用Unsafe类的内存分配方法可以实现超大数组。实际上这样的数据就可以认为是C数组,因此需要注意在合适的时间释放内存。

五、多线程同步。包括锁机制、CAS操作等。

这部分包括了monitorEnter、tryMonitorEnter、monitorExit、compareAndSwapInt、compareAndSwap等方法。

其中monitorEnter、tryMonitorEnter、monitorExit已经被标记为deprecated,不建议使用。

Unsafe类的CAS操作可能是用的最多的,它为Java的锁机制提供了一种新的解决办法,比如AtomicInteger等类都是通过该方法来实现的。compareAndSwap方法是原子的,可以避免繁重的锁机制,提高代码效率。这是一种乐观锁,通常认为在大部分情况下不出现竞态条件,如果操作失败,会不断重试直到成功。

六、挂起与恢复。

这部分包括了park、unpark等方法。

将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。

七、内存屏障。

这部分包括了loadFence、storeFence、fullFence等方法。这是在Java 8新引入的,用于定义内存屏障,避免代码重排序。

loadFence() 表示该方法之前的所有load操作在内存屏障之前完成。同理storeFence()表示该方法之前的所有store操作在内存屏障之前完成。fullFence()表示该方法之前的所有load、store操作在内存屏障之前完成。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对java学习网的支持。

相关下载

  • Java面向对象编程(第2版)

    大小:136 MB
  • 大话Java:从零基础到数据库、Web开发

    大小:66.74MB
  • Java语言程序设计:基础篇(第6版)

    大小:62.7 KB
  • Java从入门到精通(第4版)

    大小:292.7 MB

相关教程

  • JavaMail发送(带图片和附件)和接收邮件实现详解(四)

    JavaMail发送(带图片和附件)和接收邮件实现详解(四)

    给大家整理一篇关于Java的教程,这篇文章主要为大家详细介绍了JavaMail带图片和附件的发送和接收邮件实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    发布时间:2022-06-12主题:

    查看详情
  • Java统计字符串中字符出现次数的方法示例

    Java统计字符串中字符出现次数的方法示例

    给大家整理一篇关于Java的教程,这篇文章主要介绍了Java统计字符串中字符出现次数的方法,涉及Java针对字符串的遍历、查找、计算等相关操作技巧,需要的朋友可以参考下

    发布时间:2022-06-10主题:

    查看详情
  • java各种数据类型的互相转换实例代码

    给大家整理了关于java的教程,这篇文章主要介绍了java 各种数据类型的互相转换实例代码,需要的朋友可以参考下

    发布时间:2022-06-12主题:java数据类型的互相转换

    查看详情
  • Java构建JDBC应用程序的实例操作

    为网友们分享了关于Java的教程,在本篇文章里小编给大家整理了一篇关于Java构建JDBC应用程序的实例操作,有兴趣的朋友们可以学习参考下。

    发布时间:2022-06-12主题:Java构建JDBC应用的操作

    查看详情
  • Java序列化常见实现方法代码实例

    给网友朋友们带来一篇关于Java的教程,这篇文章主要介绍了Java序列化常见实现方法代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    发布时间:2022-06-10主题:Java序列化

    查看详情
  • Java实战之超市收银管理系统的实现

    Java实战之超市收银管理系统的实现

    给网友朋友们带来一篇关于java的教程,这篇文章主要介绍了如何利用Java实现超市收银管理系统,文中采用的技术有:Spring、SpringMVC、MyBatis、ThymeLeaf等,需要的可以参考一下

    发布时间:2022-06-11主题:Java收银系统

    查看详情
  • Java的接口和抽象类深入理解

    给网友朋友们带来一篇关于java的教程,这篇文章主要介绍了Java的接口和抽象类深入理解的相关资料,希望通过本文大家能够理解应用接口与抽象类的使用方法,需要的朋友可以参考下

    发布时间:2022-06-11主题:

    查看详情
  • Java中的Random()函数及两种构造方法

    给大家整理一篇关于java的教程,Java中存在着两种Random函数分别是java.lang.Math.Random和java.util.Random,文中给大家介绍了random()的两种构造方法,感兴趣的朋友跟随小编一起看看吧

    发布时间:2022-06-10主题:

    查看详情

用户留言