阅读更多
1 前言
Unsafe这个类是用于执行低级别、不安全操作的方法集合。尽管这个类和所有的方法都是公开的(public),但是这个类的使用仍然受限,你无法在自己的java程序中直接使用该类,因为只有授信的代码才能获得该类的实例
Java最初被设计为一种安全的受控环境。尽管如此,HotSpot还是包含了一个后门sun.misc.Unsafe,提供了一些可以直接操控内存和线程的底层操作。Unsafe被JDK广泛应用于java.nio和并发包等实现中,这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改,但是不建议在生产环境中使用
在JDK标准库的实现中许多地方会出现Unsafe的身影,因此了解一下Unsafe还是有必要的
2 put/get
以int类型为例进行说明,其他基本类型以及Object类似
3 getInt
该方法从给定的对象中取出指定偏移量(offset)的int类型的字段
当满足下列条件之一时,结果才是正确的,否则结果是未定义的
offset
是通过objectFieldOffset
方法获取,并且o
的类型与该字段所属的类型兼容offset
与o
是通过staticFieldOffset
方法与staticFieldBase
方法获取o
的类型是数组,且offset = B + N * S
,其中B
通过arrayBaseOffset
方法获取,即数组的起始偏移量;S
通过arrayIndexScale
方法获取,即数组单个元素的偏移量;N
代表第N个元素
1 | /** |
3.1 putInt
putInt将值x
存入对象o
的指定偏移量offset
中
1 | /** |
3.2 else
这里仅列出其他所有基本类型的put/get方法,具体说明请参考putInt和getInt方法
1 | /** |
4 putVolatile/getVolatile
这类方法从指定对象中以volatile的方式读取或者写入相应类型的值。等效于给相应的字段加上volatile关键字,即实现volatile读写的内存语义(插入相应的内存屏障)
那为什么不直接使用volatile关键字来修饰呢?因为只想在某些特定的地方拥有volatile读写的内存语义,这样可以提高效率,如果粗暴地直接加上volatile关键字,那么可能会导致性能的下降。这种优化手段一般我们不需要考虑,这是JDK标准库实现才会使用的手法,毕竟Unsafe是不推荐正常Java代码使用的
1 | /** |
5 putOrder/getOrder
这类方法从指定对象中读取或者写入相应类型的值
- putOrder等效于插入
StoreStore
屏障 - getOrder等效于插入
LoadLoad
屏障
1 | /** |
6 park/unpark
unpark()方法可以唤醒一个线程,如果线程处于非阻塞状态则获取一枚许可,但是多次调用unpark()方法也仅能获取一枚许可
park()方法用于消耗一枚许可,当没有可用许可时便阻塞指定线程。即如果在调用park()方法之前调用过unpark()方法,那么本次park()将不会阻塞该线程
1 | /** |
7 CAS
CAS即compare and swap,比较当前值与期望值,如果相等,那么替换为指定值,如果不相等,什么也不做。该操作是原子操作
1 | /** |
8 offset
这类方法用于获取内存偏移量,这些偏移量在Java代码中是没用的,因为Java完全屏蔽了内存结构,这些偏移量只用于配合Unsafe的put、get方法
8.1 staticFieldOffset
返回指定静态字段在其所属类型的内存结构中的偏移量。任意一个字段的offset与base都是相同的,任意两个不同的字段都不可能有相同的偏移量(废话)
1 | /** |
8.2 objectFieldOffset
返回指定实例字段在其所属类型的内存结构中的偏移量
1 | /** |
8.3 staticFieldBase
1 | /** |
8.4 arrayBaseOffset
返回数组类型中第一个元素的偏移量,因为Java中数组的内存结构中并不仅有元素的内存空间,还有一些额外的信息需要存储,比如Mark word,元数据指针,数组长度等等。因此数组中第一个元素的相对偏移量(相对于数组起始地址)并不是0
1 | /** |
8.5 arrayIndexScale
返回数组中每个元素所占的偏移量?
1 | /** |
9 获取Unsafe实例
Unsafe类是如此地不安全,以至于JDK开发者增加了很多特殊限制来访问它
- 私有的构造器
- 工厂方法getUnsafe()的调用器只能被Bootloader加载,否则抛出SecurityException 异常
不过,我们可以通过反射机制轻松获取Unsafe的一个实例
1 | public static Unsafe getUnsafe(){ |