Unsafe (version 1.8)

JAVA concurrent source code version 1.8


Enter the text here

  • Unsafe (version 1.8)
    • 1. Review the Unsafe
    • 2.Unsafe data structures
      • 2.1 the class definition
      • 2.2 the constructor
      • 2.3 Important Variables
    • Unsafe is the most important method
    • 4. The use of Unsafe
      • 4.1 UnSafe Usage restrictions
        • 4.1.1 Private constructor
        • 4.1.2 Prohibited factory methods
      • 4.2 Unsafe Reflection Acquisition

1. Review the Unsafe

  • Unsafe is a backclass that encapsulates pointer-like operations, providing low-level operations that directly manipulate memory and threads
  • Usage: Unsafe is widely used in the JDK for NIO packages and unbundled packages, but is not recommended for production environments because it is too risky
  • Unsafe: Unsafe refers to unsafe manipulation of Pointers (hence Java’s removal of Pointers). If a pointer points to the wrong position or calculates the offset of a pointer, the result is unexpected, such as overwriting someone else’s memory.
  • Bonus 1: Given the opportunity to open a JVM, I would like to reexamine the implementation of some important methods from the JVM source perspective
  • Add 2:This time forAnd @aQS frameworkA piece of wheat in the process of production

2.Unsafe data structures

2.1 the class definition

public final class UnsafeCopy the code

2.2 the constructor

Private Unsafe() {}Copy the code

2.3 Important Variables

private static final Unsafe theUnsafe; public static final int INVALID_FIELD_OFFSET = -1; public static final int ARRAY_BOOLEAN_BASE_OFFSET; public static final int ARRAY_BYTE_BASE_OFFSET; public static final int ARRAY_SHORT_BASE_OFFSET; public static final int ARRAY_CHAR_BASE_OFFSET; public static final int ARRAY_INT_BASE_OFFSET; public static final int ARRAY_LONG_BASE_OFFSET; public static final int ARRAY_FLOAT_BASE_OFFSET; public static final int ARRAY_DOUBLE_BASE_OFFSET; public static final int ARRAY_OBJECT_BASE_OFFSET; public static final int ARRAY_BOOLEAN_INDEX_SCALE; public static final int ARRAY_BYTE_INDEX_SCALE; public static final int ARRAY_SHORT_INDEX_SCALE; public static final int ARRAY_CHAR_INDEX_SCALE; public static final int ARRAY_INT_INDEX_SCALE; public static final int ARRAY_LONG_INDEX_SCALE; public static final int ARRAY_FLOAT_INDEX_SCALE; public static final int ARRAY_DOUBLE_INDEX_SCALE; public static final int ARRAY_OBJECT_INDEX_SCALE; public static final int ADDRESS_SIZE; private static native void registerNatives(); static { registerNatives(); Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"}); theUnsafe = new Unsafe(); / / the singleton pattern - hungry type ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe. ArrayBaseOffset (Boolean [] class); ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class); ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class); ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class); ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class); ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class); ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class); ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class); ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class); ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class); ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class); ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class); ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class); ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class); ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class); ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class); ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class); ADDRESS_SIZE = theUnsafe.addressSize(); }Copy the code

Unsafe is the most important method

Public native int getInt(Object var1, long var2); Public native void putInt(Object var1, long var2, int var4); public native Object getObject(Object var1, long var2); public native void putObject(Object var1, long var2, Object var4); / /... Also Boolean, Byte, Char, Short, Long, Float, Double get\set.... Public native long allocateMemory(long var1); Public native long reallocateMemory(long var1, long var3); public native void setMemory(Object var1, long var2, long var4, byte var6); public void setMemory(long var1, long var3, byte var5) { this.setMemory((Object)null, var1, var3, var5); } public native void copyMemory(Object var1, Long var2, Object var4, Long var5, long var7); public void copyMemory(long var1, long var3, long var5) { this.copyMemory((Object)null, var1, (Object)null, var3, var5);  } public native void freeMemory(long var1); Public Native Long staticFieldOffset(Field var1); public native long objectFieldOffset(Field var1); public native Object staticFieldBase(Field var1); public native void ensureClassInitialized(Class<? > var1); //arrayBaseOffset and arrayIndexScale can be used to locate each element in the array in memory // Get the offset address of the first element of the array public native int arrayBaseOffset(Class<? > var1); Public native int arrayIndexScale(Class<? > var1); public native int addressSize(); public native int pageSize(); Public native Class<? > defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6); public native Class<? > defineClass(String var1, byte[] var2, int var3, int var4); public native Class<? > defineAnonymousClass(Class<? > var1, byte[] var2, Object[] var3); Public native Object allocateInstance(Class<? > var1) throws InstantiationException; @deprecated public void monitorEnter(Object var1); public native void monitorExit(Object var1); public native boolean tryMonitorEnter(Object var1); Public native void throwException(Throwable var1); //CAS operation /** * compare the value at obj offset with the expected value, if the same, update, This update is non-interruptible * @param obj The object to be updated * @param offset The offset of the integer field in obj * @param expect the value to exist in the field * @param update If expected expect is the same as the current value of field, Return Return true */ Public final Native Boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6); Public native Object getObjectVolatile(Object var1, Long var2); public native void putObjectVolatile(Object var1, long var2, Object var4); public native int getIntVolatile(Object var1, long var2); Public native void putIntVolatile(Object var1, long var2, int var4); / /... There are also Boolean, Byte, Char, Short, Long, Float, Double volatile get\put.... public native void putDoubleVolatile(Object var1, long var2, double var4); public native void putOrderedObject(Object var1, long var2, Object var4); public native void putOrderedInt(Object var1, long var2, int var4); public native void putOrderedLong(Object var1, long var2, long var4); //LockSupport - Suspend and wake up a thread public native void unpark(Object var1); public native void park(boolean var1, long var2); public native int getLoadAverage(double[] var1, int var2); Public final int getAndAddInt(Object var1, Long var2, int var4) {int var5; public final int getAndAddInt(Object var1, long var2, int var4) {int var5; do { var5 = this.getIntVolatile(var1, var2); } while(! this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; } public final int getAndSetInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(! this.compareAndSwapInt(var1, var2, var5, var4)); return var5; } / /... And thread-safe add and set operations for Long and Object... Public native void loadFence(); public native void storeFence(); public native void fullFence();Copy the code

4. The use of Unsafe

4.1 UnSafe Usage restrictions

  • Because Unsafe is risky to use, the JDK adds a number of restrictions to access it: singleton schemas that forbid access

4.1.1 Private constructor

private Unsafe() {}Copy the code

4.1.2 Prohibited factory methods

@CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); // This method is used to determine if the caller's class loader is the system core loader (i.e. the Bootstrap loader). VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; }}Copy the code
  • Let’s first explicitly call the factory method to see the result
package concurrent; import sun.misc.Unsafe; public class UnsafeDemo { public static void main(String[] args) { Unsafe.getUnsafe(); }} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - / / output: the Exception in the thread "is the main" Java. Lang. SecurityException: Unsafe at sun. Misc. Unsafe. GetUnsafe (Unsafe. Java: 90) at concurrent. UnsafeDemo. Main (UnsafeDemo. Java: 7) / / analysis: You can see that a direct call will throw a security exception because the classloader is an AppClassLoader and not a BootstrapLoaderCopy the code

! [QQ screenshots 20170830155001. PNG – 60.7 kB] [2]

  • A further elaboration of the vm. isSystemDomainLoader method
  • According to how Java class loaders work, application classes are loaded by AppLoader and system core classes are loaded by BootstrapLoader
  • When a class has a null classloader, it is loaded by BootstrapLoader. This class is a system core class (for example, in the rt.jar package).
  • When a class cannot be loaded by BootstrapLoader, the class loader is usually AppClassLoader, which is a custom class

4.2 Unsafe Reflection Acquisition

// public static Unsafe getUnsafe(){try {// get theUnsafe theUnsafe variable, Namely the Unsafe instance object Field f = Unsafe. Class. GetDeclaredField (" theUnsafe "); f.setAccessible(true); // Field is static; // See: private static final Unsafe theUnsafe; return (Unsafe) f.get(null); } catch (Exception e) { e.printStackTrace(); } return null; }Copy the code