The problem
(1) What is Unsafe?
(2) Does Unsafe only have CAS functions?
(3) What is Unsafe about food?
(4) How to use Unsafe?
Introduction to the
Unaddressed is the first chapter on Java and unpacking, but instead of unpacking Java classes, its magic class sun.misc.unsafe.
Unsafe gives us access to low-level mechanisms that are only for use by the Java core library and should not be used by ordinary users.
However, in order to better understand the Java ecosystem, we need to learn about it, to understand it, not to dive into the underlying C/C++ code, but to understand its basic functionality.
Gets an instance of Unsafe
Looking at Unsafe’s source code, it provides a static method for getUnsafe().
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
Copy the code
However, calling this method directly throws a SecurityException, because Unsafe is only for Use by Java inner classes and should not be used by external classes.
So, we don’t have a way?
Of course not! We have reflexes! Looking at the source code, we found that it has a property called theUnsafe, which we just need to get from reflection.
public class UnsafeTest { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); }}Copy the code
Instantiate a class using Unsafe
Suppose we have a simple class like this:
class User { int age; public User() { this.age = 10; }}Copy the code
If we instantiate the class using the constructor, the age property will return 10.
User user1 = new User(); // Print 10 system.out.println (user1.age);Copy the code
What if we call Unsafe to instantiate?
User user2 = (User) unsafe.allocateInstance(User.class); // Prints 0 system.out.println (user2.age);Copy the code
Age will return 0, because unsafe.allocateInstance () only allocates memory to the object and does not call the constructor, so only the default value 0 of int will be returned.
Modify the value of a private field
Using the Unsafe putXXX() method, we can modify the value of any private field.
public class UnsafeTest { public static void main(String[] args) throws Exception { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); User user = new User(); Field age = user.getClass().getDeclaredField("age"); unsafe.putInt(user, unsafe.objectFieldOffset(age), 20); // Print 20 system.out.println (user.getage ()); } } class User { private int age; public User() { this.age = 10; } public int getAge() { return age; }}Copy the code
Once we get the field age through the reflection call, we can change its value to any other int value using Unsafe. (Of course, this can also be modified directly by reflection)
Throwing checked Exceptions
We know that if our code throws a Checked exception, we can use try… Catch catches it or defines the exception on the method signature, whereas with Unsafe we can throw a checked exception without having to catch or define it on the method signature.
Throws IOException on the method signature. Public static void readFile() throws IOException {throw new IOException (); Public static void readFileUnsafe() {unbroadening. ThrowException (new IOException()); }Copy the code
Use out-of-heap memory
If the process runs out of memory on the JVM, this can lead to frequent GC. Ideally, we can consider using off-heap memory, which is a piece of memory that is not managed by the JVM.
With Unsafe’s allocateMemory(), we can allocateMemory directly out of the heap, which can be very useful, but remember that this memory is not managed by the JVM, so we’ll call the freeMemory() method to manually free it.
Suppose we want to create a huge array of ints outside the heap, we can do this using the allocateMemory() method:
Class OffHeapArray {private static final int = 4; private long size; private long address; private static Unsafe unsafe; static { 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(); }} public OffHeapArray(long size) {this.size = size; // address = unsafe. AllocateMemory (size * INT); Public int get(long I) {return unsafe. GetInt (address + I * int); Unsafe. putInt(address + I * int, value); unsafe.putInt(address + I * int, value); } public long size() {return size; } public void freeMemory() {unsafe.freememory (address); }}Copy the code
Call allocateMemory() in the constructor to allocateMemory, and call freeMemory() to freeMemory when use is complete.
The usage is as follows:
OffHeapArray offHeapArray = new OffHeapArray(4); OffHeapArray. Set (0, 1); OffHeapArray. Set (1, 2); OffHeapArray. Set (2, 3); OffHeapArray. Set (3, 4); OffHeapArray. Set (2, 5); Int sum =0; for(int i=0; i < offHeapArray.size(); i++){ sum += offHeapArray.get(i); } // print 12 system.out.println (sum); offHeapArray.freeMemory();Copy the code
Finally, be sure to call freeMemory() to freeMemory back to the operating system.
CompareAndSwap operation
CAS operations are heavily used under JUC, underpinned by calls to the Unsafe CompareAndSwapXXX() method. This approach is widely used in lock-free algorithms and can take advantage of CAS processor instructions to provide significant acceleration over the standard pessimistic locking mechanism in Java.
For example, we can build thread-safe counters based on Unsafe’s compareAndSwapInt() method.
We define a volatile field count so that changes to it are visible to all threads and obtain the offset address of count in the class when the class is loaded.
In the increment() method, we attempt to update the previously acquired count value by calling Unsafe’s compareAndSwapInt() method. If it has not been updated by another thread, the update succeeds; otherwise, we retry until it succeeds.
We can test our code by using multiple threads:
Park/Unpark operations
The JVM uses the unsafe-looking methods Park () and unpark() for context switches.
The JVM calls Unsafe’s park() method to block a thread that is waiting for an operation.
The JVM calls the Unsafe unpark() method to wake up a blocked thread when it needs to run again.
We saw a lot of locksupport.park ()/unpark() when analyzing collections in Java earlier, both of which are underlying calls to the Unsafe methods.
conclusion
Using Unsafe, you can do almost anything:
1) Instantiate a class;
(2) Modify the value of the private field;
(3) Throw a checked exception;
(4) Use out-of-heap memory;
(5) CAS operation;
(6) block/wake up the thread;
eggs
How to instantiate a class?
(1) Instantiate a class using a constructor;
(2) Instantiate a Class by Class;
(3) Instantiate a class by reflection;
(4) instantiate a class by cloning;
(5) Instantiate a class by deserialization;
(6) Instantiate a class via Unsafe;
Author: Tong Elder brother read source link: mp.weixin.qq.com/s?__biz=Mzk… Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.