Java 1.8 Unsafe

Posted randomsort

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 1.8 Unsafe相关的知识,希望对你有一定的参考价值。

Unsafe 类在 sun.misc 包下,不属于Java标准。但是很多 Java 的基础类库,以及优秀的三方库都会用这个提升性能。

 

Unsafe 使用了单例模式,想使用 Unsafe 类就需要获取实例。由于安全限制,不能用一般的方法获取这个实例,通常都是使用反射获取

public class UnsafeDemo {
    static sun.misc.Unsafe U;
    
    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            U = (Unsafe) f.get(null);
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}

 

Unsafe 类几类功能:

内存管理

long allocateMemory(long bytes)

  向操作系统申请一块本地内存,大小为 bytes 字节,返回内存块的地址。本地内存是指不由 JVM 管理的内存,不会被 GC 管理。

  底层使用 malloc 实现

 

long reallocateMemory(long address, long bytes)

  resize 一块本地内存,address 是原内存地址, bytes 是新大小。

  如果 address 是 0,则内部用 allocateMemory 分配新内存;如果 bytes 是 0,则用 freeMemory 释放原内存。

  底层使用 realloc 实现。

 

void freeMemory(long address)

  释放由 allocateMemory 申请的内存

  底层用 free 实现

 

int pageSize()

  返回一页内存的大小

 

int addressSize()

  返回一个指针的大小

 

内存操作

内存操作需要提供地址。UnSafe 需要地址的场合会需要两个参数 Object o, long offset

  如果 o 是 null, offset 将被视为具体的内存地址;

  如果 o 非 null,offset 被为字段在对象或数组中的偏移。 o 和 offset 一起得到一个有效地址

 

void setMemory(Object o, long offset, long bytes, byte value)

  将一块内存设置为固定值。

void setMemory(long address, long bytes, byte value)

  等价于 setMemory(null, address, bytes, value);

 

void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes)

  复制内存

void copyMemory(long srcAddress, long destAddress, long bytes)

  等价于 copyMemory(null, srcAddress, null, destAddress, bytes)

 

put / get 系列

T getT(Object o, long offset)

void putT(Object o, long offset, T x) 

  T 可以是 int、boolean、byte、short、char、long、float、double

  另外还有不需要 Object o 参数的版本,等价于 getT(null, address)

 

Object getObject(Object o, long offset)

void putObject(Object o, long offset, Object x)

 

T     getTVolatile(Object o, long offset) 

void    putTVolatile(Object o, long offset, T x)

  带 volatile 语义的 put / get

 

long getAddress(Object o, long offset)

  从指定地址获取一个内存指针

 

void putAddress(Object o, long offset, long x)

  将指针存到指定地址

 

void putOrderedObject(Object o, long offset, Object x)

void putOrderedInt(Object o, long offset, int x)

void putOrderedLong(Object o, long offset, long x)

  保证写后立即可见

 

计算类字段内存位置

long staticFieldOffset(Field f)

  返回一个静态字段的内存位置

 

long objectFieldOffset(Field f)

  返回一个指定字段的存储位置

 

Object staticFieldBase(Field f)

  返回一个静态字段的存储位置,是一个引用

 

非常规的对象实例化

Object allocateInstance(Class<?> cls)

  创建一个类实例,但不执行构造方法

 

数组操作

int arrayBaseOffset(Class<?> arrayClass)

  返回 arrayClass 类型数组的第 0 个元素到数组对象内存开始的偏移

 

int arrayIndexScale(Class<?> arrayClass)

  返回一个数组元素需要的长度大小

 

异常

void throwException(Throwable ee)

  该方法抛出受检异常,但代码不必捕捉或重新抛出它,正如运行时异常一样

 

动态类

Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain)

  从字节码创建一个类

 

Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches)

  从字节码创建匿名类

 

void ensureClassInitialized(Class<?> c)

  加载类

 

boolean shouldBeInitialized(Class<?> c)

  检查类是否已加载

 

多线程同步

void monitorEnter(Object obj)

  锁定对象

void monitorExit(Object obj)

  释放锁

monitorEnter 和 monitorExit 的组合相当于 synchronized 关键字

 

boolean tryMonitorEnter(Object obj)

  尝试锁定对象

 

以上 3 个都是 @Deprecated 的方法

 

原子操作

boolean compareAndSwapObject(Object o, long offset, Object expected, Object x)

boolean compareAndSwapInt(Object o, long offset, int expected, int x)

boolean compareAndSwapLong(Object o, long offset, long expected, long x)

  如果变量的值是 expected,则更新成  x,原子更新

 

int getAndAddInt(Object o, long offset, int delta)

long getAndAddLong(Object o, long offset, long delta)

  原子加

 

getAndSetInt(Object o, long offset, int newValue)

getAndSetLong(Object o, long offset, long newValue)

getAndSetObject(Object o, long offset, Object newValue)

  原子地设置新值和返回旧值

 

挂起与恢复

void park(boolean isAbsolute, long time)

  暂停当前线程

 

void unpark(Object thread)

  通知线程恢复

 

JDK concurrent 包的锁大部分用这个实现

内存屏障

void loadFence()

  在该方法之前的所有读操作,一定在load屏障之前执行完成

 

void storeFence()

  在该方法之前的所有写操作,一定在store屏障之前执行完成

 

void fullFence()

  在该方法之前的所有读写操作,一定在full屏障之前执行完成,这个内存屏障相当于上面两个的合体功能

 

以上是关于Java 1.8 Unsafe的主要内容,如果未能解决你的问题,请参考以下文章

我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段

ConCurrentHashMap在1.7和1.8区别

ConcurrentHashMap 结构 1.7 与1.8

Java操作系统硬件的方法Unsafe

java的sun.misc.Unsafe类

java 非阻塞算法实现基础:unsafe类介绍