首页 并发工具 - Unsafe
文章
取消

并发工具 - Unsafe

一. 简介

sun.misc包下的一个类, 可以像C语言一样直接使用指针进行访问内存资源。

1.1 获取方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final class Unsafe {
  // 单例对象
  private static final Unsafe theUnsafe;

  private Unsafe() {
  }
  @CallerSensitive
  public static Unsafe getUnsafe() {
    Class var0 = Reflection.getCallerClass();
    // 仅在引导类加载器`BootstrapClassLoader`加载时才合法
    if(!VM.isSystemDomainLoader(var0.getClassLoader())) {    
      throw new SecurityException("Unsafe");
    } else {
      return theUnsafe;
    }
  }
}

由于包sun.misc位于${JAVA_HOME}/lib/rt.jar中, 属于引导类加载器的加载范围,不能直接使用,于是要采用反射的方式进行调用。

1
2
3
4
5
6
7
8
9
10
private static Unsafe reflectGetUnsafe() {
    try {
      Field field = Unsafe.class.getDeclaredField("theUnsafe");
      field.setAccessible(true);
      return (Unsafe) field.get(null);
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return null;
    }
}

二. 功能

2.1 内存操作

堆外内存操作API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//分配内存, 相当于C++的malloc函数
public native long allocateMemory(long bytes);
//扩充内存
public native long reallocateMemory(long address, long bytes);
//释放内存
public native void freeMemory(long address);
//在给定的内存块中设置值
public native void setMemory(Object o, long offset, long bytes, byte value);
//内存拷贝
public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
//获取给定地址值,忽略修饰限定符的访问限制。与此类似操作还有: getInt,getDouble,getLong,getChar等
public native Object getObject(Object o, long offset);
//为给定地址设置值,忽略修饰限定符的访问限制,与此类似操作还有: putInt,putDouble,putLong,putChar等
public native void putObject(Object o, long offset, Object x);
//获取给定地址的byte类型的值(当且仅当该内存地址为allocateMemory分配时,此方法结果为确定的)
public native byte getByte(long address);
//为给定地址设置byte类型的值(当且仅当该内存地址为allocateMemory分配时,此方法结果才是确定的)
public native void putByte(long address, byte x);

Unsafe提供的堆外内存操作API, Java中操作堆外内存使用的都是这个Unsafe进行操作

2.1.1 代表应用

DirectByteBuffer, java中堆外内存的使用。在Netty, MINA等Nio框架中都有使用, 里面的实现都是通过Unsafe进行实现。

DirectByteBuffer的创建和初始化都是使用Unsafe进行分配和初始内存, 通过Cleaner进行追踪DirectByteBuffer对象的垃圾回收情况, 并在回收DirectByteBuffer的时候释放堆外内存。

Cleaner释放堆外内存的原理:

cleaner是一个phantomreference, 不影响引用对象的生命周期,在对象被回收的时候, 会让对象引用(Cleaner)进入pending链表,然后执行对象引用的clean方法。

2.2 CAS操作

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
	*  CAS
  * @param o         包含要修改field的对象
  * @param offset    对象中某field的偏移量
  * @param expected  期望值
  * @param update    更新值
  * @return          true | false
  */
public final native boolean compareAndSwapObject(Object o, long offset,  Object expected, Object update);

public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update);
  
public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);

CAS的底层实现为什么能保证其原子性呢?实际上CAS的底层操作是通过给CPU总线进行加锁, 令其他的物理处理器无法访问这一块数据, 保证了并发的时候, 只有一个物理处理器在处理这个数据, 从而保证了原子性。

2.3 线程调度

1
2
3
4
5
6
7
8
9
10
11
12
13
//取消阻塞线程
public native void unpark(Object thread);
//阻塞线程
public native void park(boolean isAbsolute, long time);
//获得对象锁(可重入锁)
@Deprecated
public native void monitorEnter(Object o);
//释放对象锁
@Deprecated
public native void monitorExit(Object o);
//尝试获取对象锁
@Deprecated
public native boolean tryMonitorEnter(Object o);

2.4 对象操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//返回对象成员属性在内存地址相对于此对象的内存地址的偏移量
public native long objectFieldOffset(Field f);
//获得给定对象的指定地址偏移量的值,与此类似操作还有:getInt,getDouble,getLong,getChar等
public native Object getObject(Object o, long offset);
//给定对象的指定地址偏移量设值,与此类似操作还有:putInt,putDouble,putLong,putChar等
public native void putObject(Object o, long offset, Object x);
//从对象的指定偏移量处获取变量的引用,使用volatile的加载语义
public native Object getObjectVolatile(Object o, long offset);
//存储变量的引用到对象的指定的偏移量处,使用volatile的存储语义
public native void putObjectVolatile(Object o, long offset, Object x);
//有序、延迟版本的putObjectVolatile方法,不保证值的改变被其他线程立即看到。只有在field被volatile修饰符修饰时有效
public native void putOrderedObject(Object o, long offset, Object x);
//绕过构造方法、初始化代码来创建对象
public native Object allocateInstance(Class<?> cls) throws InstantiationException;

参考

Java魔法类:Unsafe

Unsafe 中CAS的原子性底层实现

本文由作者按照 CC BY 4.0 进行授权

并发工具 - Reference

并发锁 - AQS详解