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

Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的,官方文档也几乎没有。Oracle正在计划从Java 9中去掉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 Unsafe相关推荐

  1. java unsafe park_Java中Unsafe类详解

    http://www.cnblogs.com/mickole/articles/3757278.html Java不能直接访问操作系统底层,而是通过本地方法来访问.Unsafe类提供了硬件级别的原子操 ...

  2. java Unsafe获取实例详细解析

    问题 1)Unsafe是什么? Unsafe作用是使用堆外内存,详情可以参考原文 2)Unsafe只有CAS的功能吗? 3)Unsafe为什么是不安全的? 4)怎么使用Unsafe? 简介 Unsaf ...

  3. java unsafe 类_Java Unsafe类的使用

    Java Unsafe类的使用 Unsafe类的作用 Unsafe类是rt.jar包中的类,它提供了原子级别的操作,它的方法都是native方法,通过JNI访问本地的C++库.它的出现是为了解决在高并 ...

  4. java unsafe获取指针_【实战Java高并发程序设计 1】Java中的指针:Unsafe类

    是<实战Java高并发程序设计>第4章的几点. 如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现.现在,就让我 ...

  5. java unsafe cas_Java Unsafe CAS 小试

    Unsafe 在 Java 标准库和框架中被大量使用,本文主要介绍如何使用 sun.misc.Unsafe 包实现 CAS 操作. Example public class UnsafeExample ...

  6. JAVA Unsafe类

    Unsafe为我们提供了访问底层的机制,这种机制仅供java核心类库使用,而不应该被普通用户使用.但是,为了更好地了解java的生态体系,我们应该去学习它,去了解它,不求深入到底层的C/C++代码,但 ...

  7. java unsafe park_Java魔法类——Unsafe应用解析

    前言 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资源.自主管理内存资源等,这些方法在提升Java运行效率.增强Java语言底层资源 ...

  8. java unsafe 类_Java的Unsafe类

    本文转载自:https://www.cnblogs.com/pkufork/p/java_unsafe.html 最近在看Java并发包的源码,发现了神奇的Unsafe类,仔细研究了一下,在这里跟大家 ...

  9. java unsafe 详解_Java CAS操作与Unsafe类详解

    一.复习 计算机内存模型,synchronized和volatile关键字简介 二.两者对比 sychronized和volatile都解决了内存可见性问题 不同点: (1)前者是独占锁,并且存在者上 ...

最新文章

  1. 【Android 安全】DEX 加密 ( Application 替换 | 获取 ContextImpl、ActivityThread、LoadedApk 类型对象 | 源码分析 )
  2. 成功解决You are using pip version 9.0.3, however version 10.0.1 is available. You should consider upgr
  3. Python基础教程:菱形继承问题
  4. FB面经Prepare: Email User
  5. Redis的存储(实现)原理
  6. php服务器 下载,php实现从服务器下载文件
  7. .Net Core3 新特性整理
  8. mysql查询特殊符号时_数据库查询中的特殊字符的问题_MySQL
  9. 软件工程学习进度第六周暨暑期学习进度之第六周汇总
  10. python机器学习案例系列教程——集成学习(Bagging、Boosting、随机森林RF、AdaBoost、GBDT、xgboost)
  11. php 什么函数获取ip,php函数获取在线ip与客户端ip
  12. 【Computer Organization笔记08】指令系统概述,指令格式,寻址方式
  13. html基本标记练习钱塘湖春行,实验1HTML基本标记的练习.doc
  14. matlab中画圆圈,如何在Matlab中绘制圆圈?
  15. 软件工程国考总结——判断题
  16. [国家集训队] 部落战争
  17. NBIOT模块基于电信IOT平台的南向对接流程
  18. 如何将Excel单独一个单元格的多个内容分散到多个单元格?简单技巧!excel怎样将一个单元格内容分隔到多个单元格?
  19. 最简容器动手小实践——FC坦克大战游戏容器化
  20. LIMS信息管理系统应用的领域有哪些?

热门文章

  1. stl源码分析de练习
  2. powerdesigner 生成实体代码 附加生成xml
  3. Codeforces686C【dfs】
  4. 自定义alert提示框
  5. 关于cocos2dx导入安卓项目至eclipse的诸多问题
  6. 数据库设计指南【转】
  7. ASP+XML+JavaScript实现动态无限级联动菜单
  8. 基于JavaScript实现配对游戏
  9. Dart 14-Day
  10. 辗转相除求最大公约数最小公倍数 扩展欧几里得算法