List of articles
- Unsafe-java The magic of
-
- Unsafe Introduction to
- Unsafe Object acquisition
-
- Append class to boot class loader BoostrapClassloader
-
- Xbootclasspath Expand
- Reflection Field obtain Unsafe Instance object 【 Recommended use 】
- Unsafe Of API
-
- Info Get information
- Objects Action object
- Classes Operation class object
- Arrays Operation array
- Synchronization Operation sync word
- Memory Operating memory
- Unsafe Realization CAS
-
- Case study :AtomicInteger Atomic operation of
Unsafe-java The magic of
Unsafe Introduction to
Unsafe Source code :http://www.docjar.com/html/api/sun/misc/Unsafe.java.html
Unsafe Class is named sun.misc.Unsafe
, As the name suggests, it’s not safe .
generally speaking , Write the underlying code or impact JVM It’s hard to achieve , Of course you can use JNI To achieve the goal ,JNI Need and C Dealing with .
stay java The platform passes sun.misc.Unsafe
Of API, You can also code at the bottom , For example, operate on the address of the target object , Directly modify the value of the address where the property field is located … Of course, using this class is dangerous , So be careful .
Unsafe A lot of use has been made in atomic classes , Can pass compareAndSwapXX
Method to call the atomic operation instructions of the underlying operating system , To perform atomic operations .
Unsafe Object acquisition
Consider creating Unsafe Before the object , Let’s take a look at the source code of this class :
public final class Unsafe {
private static final Unsafe theUnsafe;
private Unsafe() {
}
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
static {
theUnsafe = new Unsafe();
}
Unsafe Class has such characteristics :
- final Embellished
- There is a static variable as well Unsafe Instance of type
theUnsafe
- Constructor private
- Static methods getUnsafe() You can get one Unsafe Instance object theUnsafe, But checked the classloader ( Only JVM The boot loader of is allowed , Otherwise throw
SecurityException
abnormal ) - The static code block instantiates theUnsafe Variable
So we’re going to create Unsafe Instance object of , How to do it? ?
To solve the above problems . Here are two options .
Append class to boot class loader BoostrapClassloader
We can use Unsafe Class static methods getUnsafe(), But this method checks if the classloader is BoostrapClassloader.
So we can append the path of the current class to BoostrapClassloader The scanning path down .
Expand a little bit here : obtain BoostrapClassloader Loading path :
String property = System.getProperty("sun.boot.class.path"); for (String s : property.split(";")) { System.out.println(s); }
Output :
C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_211\jre\classes
Expand : obtain Extend Classloader load path :
String property2 = System.getProperty("java.ext.dirs"); for (String s : property2.split(";")) { System.out.println(s); }
Output :
C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext
C:\Windows\Sun\Java\lib\ext
Xbootclasspath Expand
Java The command line provides how to extend BoostrapClassloader The easy way to .
-Xbootclasspath: new jar
Replace completely jdk Of course Java class Search path , Don’t suggest ;-Xbootclasspath/a: Additional jar
Added in jdk Of java class After the search path , Very practical ( Multiple jar stay unix Colon separated ,windows Semicolons separate );-Xbootclasspath/p: On the front jar
discharge jdk Of java class In front of the search path , Don’t suggest ; To avoid unnecessary conflict .
So we can go through the IDEA Set in jvm Runtime parameters ( add to VM options):
-Xbootclasspath/a:D:\framework\concurrent\target\concurrent-1.0-SNAPSHOT.jar
Again run that will do . Pay attention to the packing here jar, To add
/*
Add at run time VM options
-Xbootclasspath/a:D:\framework\concurrent\target\concurrent-1.0-SNAPSHOT.jar
*/
Unsafe unsafe0 = Unsafe.getUnsafe();
System.out.println("-Xbootclasspath/a: add to jar package :" + unsafe0); // You can get Unsafe Instance object
This way is too difficult … So let’s use the second way .
Reflection Field obtain Unsafe Instance object 【 Recommended use 】
from Unsafe According to the characteristics of , We learned that , There is a theUnsafe The variable is Unsafe An example of :
private static final Unsafe theUnsafe;
Since the constructor can’t be used , We use reflection to get the value of the field directly :
// therefore , Select reflection to get
// Because there is a single instance inside :Unsafe theUnsafe;
Class clazz = Unsafe.class;
Field field = clazz.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe)field.get(null); // Get the internal fields theUnsafe
Unsafe Of API
Unsafe Provides a large number of API(100 Multiple methods ), To operate the bottom layer .
It is mainly divided into these categories :
Info Get information
Return some underlying memory information .
- addressSize: Local pointer size , The value is usually 4 perhaps 8; The original type stored in the local block is determined by their content information .
- pageSize: Return memory page size , Bytes are units , The value is 2 Of n Power
// info
System.out.println(unsafe.pageSize()); // 4096
System.out.println(unsafe.addressSize()); // 8
Objects Action object
Provides methods for manipulating objects and their fields .
-
allocateInstance: Assign an instance object , But it doesn’t call any constructors ( Variable value not initialized )
-
public native Object allocateInstance(Class cls)
-
Example , It is interesting to :
@Data
public class UnsafeDemo {
private String name = "zs";
private int age = 18;
}
// The result of running the following code :
UnsafeDemo unsafeDemo3 = (UnsafeDemo)unsafe.allocateInstance(UnsafeDemo.class);
System.out.println(unsafeDemo3); // UnsafeDemo(name=null, age=0)
UnsafeDemo unsafeDemo1 = new UnsafeDemo();
System.out.println(unsafeDemo1); // UnsafeDemo(name=zs, age=18)
-
objectFieldOffset: Get the offset of a field of a class in memory
-
public native long objectFieldOffset(Field f);
-
Example : get UnsafeDemo Class age Offset of field in memory
long ageOffset =
unsafe.objectFieldOffset(UnsafeDemo.class.getDeclaredField("age"));
System.out.println(ageOffset); // 12
Classes Operation class object
Provide operation class object 、 Static field method .
-
staticFieldOffset: Get the offset of the static field
-
public native long staticFieldOffset(Field f);
-
Example :
@Data
public class UnsafeDemo {
private String name = "zs";
private int age = 18;
private static int status = 1;
}
// staticFieldOffset: Get the offset of the static field
Field status = UnsafeDemo.class.getDeclaredField("status");
long statusOffset = unsafe.staticFieldOffset(status);
System.out.println(statusOffset); // 104
-
defineClass : inform JVM Define a class , But don’t do security checks ; By default , Class loaders and protection domains come from the caller’s Class.
-
public native Class defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain);
-
-
defineAnonymousClass: Define a classloader that is not loaded 、 System aware classes .
-
/** * @params hostClass The context of the link , Access control , Class loader * @params data Byte array form of bytecode file * @params cpPatches If there is non empty data , The replacement data Medium 829 */ */ public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches);
-
-
ensureClassInitialized: Make sure the given class is initialized , This usually needs to be combined with getting the static field Library of the class .
-
public native void ensureClassInitialized(Class c);
-
Arrays Operation array
Encapsulation of arrays .
-
arrayBaseOffset: The offset of the first element of an array object
-
public native int arrayBaseOffset(Class arrayClass)
-
Example :
int arrayBaseOffset =
unsafe.arrayBaseOffset(new byte[]{
1, 2, 3}.getClass());
System.out.println(arrayBaseOffset); // 16
-
arrayIndexScale: Addressing factor
-
public native int arrayIndexScale(Class arrayClass);
-
Synchronization Operation sync word
Some of the underlying encapsulation of operation synchronization .
-
monitorEnter: Lock the object , Must pass
monitorExit
Release the lock .-
public native void monitorEnter(Object o);
-
-
tryMonitorEnter : Trying to get a lock
-
public native boolean tryMonitorEnter(Object o);
-
-
monitorExit: Release the lock
-
public native void monitorExit(Object o);
-
-
compareAndSwapInt:CAS It’s also a very practical way ,AtomicInteger、AtomicBoolean And so the atomic classes are all passed through Unsafe Of CAP Method to realize atomic operation .
-
/** Atomic manipulation : modify java The value of the variable is x; If the object o The offset offset( In fact, it is a field of the object ) Represents the value of the variable , At present is the expectation expected, Then change it to x, return true; If the current expectation is not expected, Do not operate , return false. */ public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
-
Example AtomicInteger#incrementAndGet Method implementation logic :
java.util.concurrent.atomic.AtomicInteger#incrementAndGet
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
sun.misc.Unsafe#getAndAddInt
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
// The spin +CAS
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
-
putIntVolatile:
putInt
Of Volatile edition-
public native void putIntVolatile(Object o, long offset, int x);
-
-
putOrderedInt:
putIntVolatile
Order of \ Inert version-
public native void putOrderedInt(Object o, long offset, int x);
-
Memory Operating memory
Direct access to memory .
-
allocateMemory: Allocate memory space , And return the offset
-
public native long allocateMemory(long bytes);
-
-
copyMemory: Copy memory space
-
// @since 1.7 public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); public void copyMemory(long srcAddress, long destAddress, long bytes) { copyMemory(null, srcAddress, null, destAddress, bytes); }
-
-
freeMemory: Free up memory
-
public native void freeMemory(long address);
-
-
getAddress: Get the memory address , Unsigned integer long
-
public native long getAddress(long address);
-
-
getInt: Get the variable value of the specified offset
-
public native int getInt(Object o, long offset);
-
-
putInt: You can change the value of a variable
-
/** Parameter one : object Parameter two : Field offset Parameter 3 : The value to set */ public native void putInt(Object o, long offset, int x);
-
Example :
// Modify the attribute value of the object instance through the magic class
UnsafeDemo unsafeDemo = new UnsafeDemo();
long ageOffset =
unsafe.objectFieldOffset(UnsafeDemo.class.getDeclaredField("age"));
unsafe.putInt(unsafeDemo, ageOffset, 30); // Change the field age To change the value of 30
Unsafe Realization CAS
Case study :AtomicInteger Atomic operation of
Example AtomicInteger#incrementAndGet Method implementation logic :
java.util.concurrent.atomic.AtomicInteger#incrementAndGet
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
sun.misc.Unsafe#getAndAddInt
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
// The spin +CAS
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
Here are some common ones API,Unsafe There are many other similar methods , Don’t list one by one .