JDK中Unsafe类详解
http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/classes/sun/misc/Unsafe.java
http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/prims/unsafe.cpp
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/misc/Unsafe.java
http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/tip/src/share/vm/prims/unsafe.cpp
案例代码
package com.dsp.unsafe; import java.io.Serializable; import java.lang.reflect.Field; import java.util.Arrays; import java.util.concurrent.locks.ReentrantLock; import com.alibaba.fastjson.JSON; import com.dsp.json.Person; import sun.misc.Unsafe; @SuppressWarnings("restriction") public class UnsafeDemo { static class Test { private final int x; Test(int x) { this.x = x; System.out.println("Test ctor"); } int getX() { return x; } } public static void main(String[] args) throws InstantiationException, NoSuchFieldException { // 获得一个UnSafe实例 Unsafe unsafe = null; try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); unsafe = (Unsafe) f.get(null); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } if (unsafe != null) { try { // 构造一个对象,且不调用其构造函数 Test test = (Test) unsafe.allocateInstance(Test.class); // 得到一个对象内部属性的地址 long x_addr = unsafe.objectFieldOffset(Test.class.getDeclaredField("x")); // 直接给此属性赋值 unsafe.getAndSetInt(test, x_addr, 47); System.out.println(test.getX()); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } // 通过地址操作数组 if (unsafe != null) { final int INT_BYTES = 4; int[] data = new int[10]; System.out.println(Arrays.toString(data)); long arrayBaseOffset = unsafe.arrayBaseOffset(int[].class); System.out.println("Array address is :" + arrayBaseOffset); long arrayBaseOffset2 = unsafe.arrayBaseOffset(double[].class); System.out.println("Array address is :" + arrayBaseOffset2); unsafe.putInt(data, arrayBaseOffset, 47); unsafe.putInt(data, arrayBaseOffset + INT_BYTES * 8, 43); System.out.println(Arrays.toString(data)); } // CAS if (unsafe != null) { Test test = (Test) unsafe.allocateInstance(Test.class); long x_addr = unsafe.objectFieldOffset(Test.class.getDeclaredField("x")); unsafe.getAndSetInt(test, x_addr, 47); unsafe.compareAndSwapInt(test, x_addr, 47, 78); System.out.println("After CAS:" + test.getX()); } } @SuppressWarnings("deprecation") public static void mainB(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); Unsafe UNSAFE = (Unsafe) theUnsafe.get(null); System.out.println(UNSAFE); byte[] data = new byte[10]; System.out.println(Arrays.toString(data)); int byteArrayBaseOffset = UNSAFE.arrayBaseOffset(byte[].class); System.out.println(byteArrayBaseOffset); UNSAFE.putByte(data, byteArrayBaseOffset, (byte) 1); UNSAFE.putByte(data, byteArrayBaseOffset + 5, (byte) 5); System.out.println(Arrays.toString(data)); UNSAFE.setMemory(data, byteArrayBaseOffset, 1, (byte) 2); UNSAFE.setMemory(data, byteArrayBaseOffset + 5, 1, (byte) 6); System.out.println(Arrays.toString(data)); } @SuppressWarnings({ "unused", "rawtypes" }) public static void mainA(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); long allocateMemory = unsafe.allocateMemory(1024); long theUnsafeOffset = unsafe.staticFieldOffset(field); System.out.println(theUnsafeOffset); /******************************************************************************** * 获取对象中某字段在内存中的偏移量 */ // 开始使用unsafe对象,分别找到Person对象中name属性和age属性的内存地址偏移量 // 首先是Person类中的name属性,在内存中设定的偏移位置 Field field2 = Person.class.getDeclaredField("name"); // 一旦这个类实例化后,该属性在内存中的偏移位置 long offset2 = unsafe.objectFieldOffset(field2); System.out.println("name offset = " + offset2); /* * 然后是Person类中的age属性,在内存中设定的偏移位置 */ Field age3 = Person.class.getDeclaredField("age"); long ageOffset3 = unsafe.objectFieldOffset(age3); System.out.println("age offset = " + ageOffset3); /******************************************************************************** * 修改某个字段的数据 */ /* * 修改字段数据 */ Person person = new Person(); person.setName("dsp"); person.setAge(20); /* * 获取age属性的内存地址偏移量 */ Field ageField = Person.class.getDeclaredField("age"); long ageOffset = unsafe.objectFieldOffset(ageField); /* * 比较并修改值 1、需要修改的对象 2、更改属性的内存偏移量 3、预期的值 4、设置的新值 */ if (unsafe.compareAndSwapInt(person, ageOffset, 20, 26)) { System.out.println("修改数据成功"); } else { System.out.println("修改数据失败"); } System.out.println(JSON.toJSONString(person)); int ss, ts; try { Class<Segment[]> sc = Segment[].class; SBASE = unsafe.arrayBaseOffset(sc); ss = unsafe.arrayIndexScale(sc); } catch (Exception e) { throw new Error(e); } SSHIFT = 31 - Integer.numberOfLeadingZeros(ss); System.out.println("SBASE=" + SBASE); System.out.println("ss=" + ss); System.out.println("SSHIFT=" + SSHIFT); int ARRAY_INT_BASE_OFFSET = unsafe.arrayBaseOffset(int[].class); int ARRAY_INT_INDEX_SCALE = unsafe.arrayIndexScale(int[].class); System.out.println("ARRAY_INT_BASE_OFFSET=" + ARRAY_INT_BASE_OFFSET); System.out.println("ARRAY_INT_INDEX_SCALE=" + ARRAY_INT_INDEX_SCALE); } // Unsafe mechanics private static long SBASE; private static long SSHIFT; static final class Segment<K, V> extends ReentrantLock implements Serializable { /* * Segments maintain a table of entry lists that are always kept in a consistent * state, so can be read (via volatile reads of segments and tables) without * locking. This requires replicating nodes when necessary during table * resizing, so the old lists can be traversed by readers still using old * version of table. * * This class defines only mutative methods requiring locking. Except as noted, * the methods of this class perform the per-segment versions of * ConcurrentHashMap methods. (Other methods are integrated directly into * ConcurrentHashMap methods.) These mutative methods use a form of controlled * spinning on contention via methods scanAndLock and scanAndLockForPut. These * intersperse tryLocks with traversals to locate nodes. The main benefit is to * absorb cache misses (which are very common for hash tables) while obtaining * locks so that traversal is faster once acquired. We do not actually use the * found nodes since they must be re-acquired under lock anyway to ensure * sequential consistency of updates (and in any case may be undetectably * stale), but they will normally be much faster to re-locate. Also, * scanAndLockForPut speculatively creates a fresh node to use in put if no node * is found. */ private static final long serialVersionUID = 2249069246763182397L; /** * The maximum number of times to tryLock in a prescan before possibly blocking * on acquire in preparation for a locked segment operation. On multiprocessors, * using a bounded number of retries maintains cache acquired while locating * nodes. */ static final int MAX_SCAN_RETRIES = Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1; } }
:)