Java中Unsafe使用詳解
Unsafe介紹
Unsafe是位于sun.misc包下的一個(gè)類,主要提供一些用于執(zhí)行低級(jí)別、不安全操作的方法,如直接訪問(wèn)系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等,這些方法在提升Java運(yùn)行效率、增強(qiáng)Java語(yǔ)言底層資源操作能力方面起到了很大的作用。但由于Unsafe類使得Java語(yǔ)言擁有了類似C語(yǔ)言指針一樣操作內(nèi)存空間的能力,這無(wú)疑也增加了程序發(fā)生相關(guān)指針問(wèn)題的風(fēng)險(xiǎn)。在程序中過(guò)度、不正確使用Unsafe類會(huì)使得程序出錯(cuò)的概率變大,使得Java這種安全的語(yǔ)言變得不再“安全”,因此對(duì)Unsafe的使用一定要慎重。
java.util.concurrent.atomic包下的原子操作類,基本都是使用Unsafe實(shí)現(xiàn)的。
Unsafe提供的API大致可分為內(nèi)存操作、CAS、Class、對(duì)象操作、線程、系統(tǒng)信息獲取、內(nèi)存屏障、數(shù)組操作等幾類。
內(nèi)存相關(guān)
CAS相關(guān)
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);
- }
線程相關(guān)
LockSupport類中有應(yīng)用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相關(guān)
對(duì)象操作相關(guān)
系統(tǒng)相關(guān)
內(nèi)存屏障
loadFence:保證在這個(gè)屏障之前的所有讀操作都已經(jīng)完成。
storeFence:保證在這個(gè)屏障之前的所有寫操作都已經(jīng)完成。
fullFence:保證在這個(gè)屏障之前的所有讀寫操作都已經(jīng)完成。
在java8中 有這個(gè)StampedLock類,該類中應(yīng)用了內(nèi)存屏障功能。
- 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實(shí)例
Unsafe類是final且是單例的,并且theUnsafe字段是private;通過(guò)如下方法獲取實(shí)例
方法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簡(jiǎn)單應(yīng)用
- int i = 0 ;
- public static void main(String[] args) throws Exception {
- UnsafeDemo d = new UnsafeDemo() ;
- // 獲取Unsafe實(shí)例
- Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe") ;
- theUnsafe.setAccessible(true) ;
- Unsafe unsafe = (Unsafe) theUnsafe.get(null) ;
- // 獲取類的實(shí)例變量
- Field f = UnsafeDemo.class.getDeclaredField("i") ;
- // 獲取字段相對(duì)Java對(duì)象的"起始地址"的偏移量
- long fieldOffset = unsafe.objectFieldOffset(f) ;
- System.out.println(fieldOffset) ;
- // 設(shè)置值
- boolean success = unsafe.compareAndSwapInt(d, fieldOffset, 0, 10) ;
- System.out.println(success) ;
- System.out.println(d.i) ;
- }
Unsafe對(duì)象操作
- 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();
- }
- }
執(zhí)行結(jié)果:
對(duì)象操作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創(chuàng)建對(duì)象
當(dāng)不知道即將使用的對(duì)象有何構(gòu)造函數(shù),或是不想使用現(xiàn)有對(duì)象的構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),可以通過(guò)如下方式:
- 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簡(jiǎn)單實(shí)現(xiàn)原子操作類
- 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);
- }
- }
完畢!!!