Unsafe

Unsafe

介绍

  • Unsafe在sun.misc包下,不属于java标准。但是很多java的基础类库,如JUC,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Hadoop、Kafka等
  • 使用Unsafe可以直接访问系统内存资源并进行自主管理,Unsafe类在提升java运行效率,增强java语言底层操作能力方面起了很大作用。
  • 官方不建议使用Unsafe

实例化私有类

public class UnsafeUse {

    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("jack");
        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;
    }
}

CAS操作

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);
}

直接内存访问

  • 用Unsafe开辟的内存空间不占用Heap空间,当然也不具有自动内存回收功能。

Unsafe源码

  • Unsafe源码中大部分都是native的方法,主要有以下几类
    • Class相关。主要提供Class和它的静态字段的操作方法
    • Object相关。主要提供Object和它的字段的操作方法
    • Array相关。主要提供数组及其中元素的操作方法
    • 并发相关。主要提供低级别同步原语,如CAS、线程调度、volatile、内存屏障等。
    • Memory相关。提供了直接内存访问方法(绕过java堆直接操作本地内存),可做到像C一样自由利用系统内存资源。
    • 系统相关。主要返回某些低级别的内存信息,如地址大小、内存页大小。

Class相关

//静态属性的偏移量,用于在对于的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);

Object相关

  • 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;

数组相关

//返回数组中的一个元素的偏移地址
public native int arrayBaseOffset(Class<?> arrayClass);

public static final int ARRAY_BOOLEAN_BASE_OFFSET= theUnsafe.arrayBaseOffset(boolean[].class);

//返回数组中每一个元素占用的大小
public native int arrayIndexScale(Class<?> arrayClass);

public static final int ARRAY_BOOLEAN_INDEX_SCALE= theUnsafe.arrayIndexScale(boolean[].class);

并发相关

  • CAS
//更新变量为X,如果当前值为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之后增加了新方法
//增加
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;
  • 线程调度相关
//取消阻塞线程
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表示获取成功
public native boolean tryMonitorEnter(Object o);
  • volatile相关读写
//从对象的指定偏移量处获取变量的引用,使用volatile的加载语义
public native Object getObjectVolatile(Object o, long offset);
  
//存储变量的引用到对象的指定偏移量出,使用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);
  • 内存屏障相关
  • java8引用,用于定义内存屏障,避免代码重排序
//禁止load重排序,即屏障前的load操作不能和屏障后的load操作调换顺序
public native void loadFence();
//禁止store重排序,即屏障前的store操作不能和屏障后的store操作重排序
public native void storeFence();
//禁止load、store重排序
public native void fullFence();
  • 直接内存访问
//(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);

  • 系统相关
//返回指针的大小。返回值为4或8。
public native int addressSize();
  
/** The value of {@code addressSize()} */
public static final int ADDRESS_SIZE = theUnsafe.addressSize();
  
//内存页的大小。
public native int pageSize();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值