相关背景
一下代码基于JDK1.8进行分析,在高版本中部分方法已经被删除获取迁移到其他地方。
Java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作 。Unsafe类使用private修饰构造方法,只能使用他自己提供的一个final类来进行获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private static native void registerNatives () ;static { registerNatives(); sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe" ); }private Unsafe () {}private static final Unsafe theUnsafe = new Unsafe ();@CallerSensitive public static Unsafe getUnsafe () { Class<?> caller = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException ("Unsafe" ); return theUnsafe; }
Unsafe类提供102个native方法,主要包含类、对象、变量的管理(获取和修改),内存管理,线程管理,内存屏障等。
1 2 3 4 5 6 7 public static Unsafe getUnsafe () throws Exception{ Field f = Unsafe.class.getDeclaredField("theUnsafe" ); f.setAccessible(true ); Unsafe unsafe = (Unsafe) f.get(null ); return unsafe; }
类、对象、变量管理 getObject 1 public native Object getObject (Object o, long offset) ;
该方法用于获取Java对象o中内存地址偏移量为offerset的对象。类似的方法还有getInt()、getDouble等。
Object o:引用对象 long offset:内存偏移量(偏移量是可以通过objectFieldOffset方法获取获取的)
1 2 3 public native long objectFieldOffset (Field f) ;public native long staticFieldOffset (Field f) ;public native int arrayBaseOffset (Class<?> arrayClass) ;
操作案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Data public class UnsafeTest { private int id; private String sex; private String name; public static Unsafe getUnsafe () throws Exception{ Field f = Unsafe.class.getDeclaredField("theUnsafe" ); f.setAccessible(true ); Unsafe unsafe = (Unsafe) f.get(null ); return unsafe; } public static void main (String[] args) throws Exception { Unsafe unsafe = getUnsafe(); UnsafeTest hello = new UnsafeTest (); hello.name = "mikey" ; Field field = UnsafeTest.class.getDeclaredField("name" ); long offset = unsafe.objectFieldOffset(field); System.out.println("offset=" +offset); Object name = unsafe.getObject(hello, offset); System.out.println(name); } }
putObject 该方法用于修改Java对象o中内存地址偏移量为offerset的对象。类似的方法还有putInt()、putDouble等。
1 public native void putObject (Object o, long offset, Object x) ;
Object o:待更新的对象 long offset:对象熟悉的偏移地址 Object x:更新后的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Data public class UnsafeTest { private int id; private String sex; private String name; public static Unsafe getUnsafe () throws Exception{ Field f = Unsafe.class.getDeclaredField("theUnsafe" ); f.setAccessible(true ); Unsafe unsafe = (Unsafe) f.get(null ); return unsafe; } public static void main (String[] args) throws Exception { Unsafe unsafe = getUnsafe(); UnsafeTest hello = new UnsafeTest (); hello.name = "mikey" ; Field field = UnsafeTest.class.getDeclaredField("name" ); long offset = unsafe.objectFieldOffset(field); System.out.println("offset=" +offset); Object name = unsafe.getObject(hello, offset); System.out.println(name); unsafe.putObject(hello,offset,"leo" ); System.out.println(hello.name); } }
getObjectVolatile getObjectVolatile方法用于获取对象o带有volatile关键字修饰的属性,和getObject方法类似。
1 Object getObjectVolatile (Object o, long offset) ;
putObjectVolatile putObjectVolatile方法用于设置对象o带有volatile关键字修饰的属性,和putObject方法类似。
1 2 3 4 5 public native void putObjectVolatile (Object o, long offset, Object x) ;
putOrderedObject