您的位置 首页 java

Java中Unsafe使用详解

环境: Java 8


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相关

Java中Unsafe使用详解

对象操作相关

Java中Unsafe使用详解

Java中Unsafe使用详解

系统相关

Java中Unsafe使用详解

内存屏障

Java中Unsafe使用详解

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

U.loadFence();

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 <Unsafe> 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<Unsafe> 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<Teacher> cons = (Constructor<Teacher>) 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);
    }

}  

完毕!!!

给个 关注+转发 谢谢啊

文章来源:智云一二三科技

文章标题:Java中Unsafe使用详解

文章地址:https://www.zhihuclub.com/176762.shtml

关于作者: 智云科技

热门文章

网站地图