【揭秘】JUC并发工具包底层机制探究,Unsafe原来这么强大!
创始人
2025-07-03 00:30:46
0

Unsafe介绍

Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使得Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。java.util.concurrent.atomic包下的原子操作类,基本都是使用Unsafe实现的。

Unsafe提供的API大致可分为内存操作、CAS、Class、对象操作、线程、系统信息获取、内存屏障、数组操作等几类。

内存相关

图片图片

CAS相关

图片图片

java.util.concurrent.atomic包中的原子类基本都用的Unsafe

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
  try {
    valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
  } catch (Exception ex) { throw new Error(ex); }
}
public final int getAndSet(int newValue) {
  return unsafe.getAndSetInt(this, valueOffset, newValue);
}

线程相关

图片图片

LockSupport类中有应用unpark,park

public static void park(Object blocker) {
  Thread t = Thread.currentThread();
  setBlocker(t, blocker);
  UNSAFE.park(false, 0L);
  setBlocker(t, null);
}
public static void unpark(Thread thread) {
  if (thread != null)
    UNSAFE.unpark(thread);
}

Class相关

图片图片

对象操作相关

图片图片

图片图片

系统相关

图片图片

内存屏障

图片图片

loadFence:保证在这个屏障之前的所有读操作都已经完成。
storeFence:保证在这个屏障之前的所有写操作都已经完成。fullFence:保证在这个屏障之前的所有读写操作都已经完成。

在java8中 有这个StampedLock类,该类中应用了内存屏障功能。

private static final sun.misc.Unsafe U;
static {
  try {
    U = sun.misc.Unsafe.getUnsafe();
  } catch (Exception e) {
    throw new Error(e);
  }
}
public boolean validate(long stamp) {
  U.loadFence();
  return (stamp & SBITS) == (state & SBITS);
}

Unsafe.java

public final class Unsafe {


  private static native void registerNatives();
  static {
    registerNatives();
    sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
  }


  private Unsafe() {}


  private static final Unsafe theUnsafe = new Unsafe();
  // ...
}

获取Unsafe实例

Unsafe类是final且是单例的,并且theUnsafe字段是private;通过如下方法获取实例。

方法1

Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
theUnsafe.setAccessible(true) ;
Unsafe unsafe = (Unsafe) theUnsafe.get(null) ;

方法2

private static Unsafe unsafe = null ;


static {
  try {
    Constructor cons = Unsafe.class.getDeclaredConstructor() ;
    cons.setAccessible(true) ;
    unsafe = cons.newInstance() ;
  } catch (Exception e) {
    e.printStackTrace();
  }
}

Unsafe简单应用

int i = 0 ;


public static void main(String[] args) throws Exception {
  UnsafeDemo d = new UnsafeDemo() ;
  // 获取Unsafe实例
  Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
  theUnsafe.setAccessible(true) ;
  Unsafe unsafe = (Unsafe) theUnsafe.get(null) ;
  // 获取类的实例变量
  Field f = UnsafeDemo.class.getDeclaredField("i") ;
  // 获取字段相对Java对象的"起始地址"的偏移量
  long fieldOffset = unsafe.objectFieldOffset(f) ;
  System.out.println(fieldOffset) ;
  // 设置值
  boolean success = unsafe.compareAndSwapInt(d, fieldOffset, 0, 10) ;
  System.out.println(success) ;
  System.out.println(d.i) ;
}

Unsafe对象操作

private static Unsafe unsafe = null ;


static {
try {
    Constructor cons = Unsafe.class.getDeclaredConstructor() ;
    cons.setAccessible(true) ;
    unsafe = cons.newInstance() ;
  } catch (Exception e) {
    e.printStackTrace();
  }
}
public static void allocate() {
  try {
    Person p = (Person)unsafe.allocateInstance(Person.class) ;
    p.setId("s001");
    System.out.println(p.getValue()) ;
    System.out.println(p.getId()) ;
  } catch (Exception e) {
    e.printStackTrace();
  }
}

执行结果:

图片图片

对象操作2:

private Person p = new Person("1", "张三") ;


public static void main(String[] args) throws Exception {
  UnSafeObjectDemo d = new UnSafeObjectDemo() ;
  Field field = Unsafe.class.getDeclaredField("theUnsafe") ;
  field.setAccessible(true) ;
  Unsafe unsafe = (Unsafe) field.get(null) ;
  Field f = d.getClass().getDeclaredField("p") ;
  long offset = unsafe.objectFieldOffset(f) ;
  System.out.println(offset) ;
  boolean res = unsafe.compareAndSwapObject(d, offset, d.p, new Person("2", "李四")) ;
  System.out.println(res) ;
  System.out.println(d.p.getName()) ;
}

图片图片

Unsafe创建对象

当不知道即将使用的对象有何构造函数,或是不想使用现有对象的构造函数创建对象时,可以通过如下方式:

Constructor cons = (Constructor) ReflectionFactory
    .getReflectionFactory()
    .newConstructorForSerialization(Teacher.class, Object.class.getConstructor());
cons.setAccessible(true) ;
Teacher t = cons.newInstance() ;
System.out.println(t) ;

Unsafe简单实现原子操作类

public class AtomicCount {


  private static Unsafe unsafe ;


  private int value ;
  private static long valueOffset ;


  static {
    try {
      Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
      theUnsafe.setAccessible(true) ;
      unsafe = (Unsafe) theUnsafe.get(null) ;


      Field f = AtomicCount.class.getDeclaredField("value") ;
      valueOffset = unsafe.objectFieldOffset(f) ;
    } catch (Exception e) {
      e.printStackTrace();
    }
  }


  public AtomicCount(int value) {
    this.value = value ;
  }


  public final int get() {
    return value;
  }


  public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
  }


}

完毕!!!

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...