Detailed explanation of Unsafe class in Java

Java cannot directly access the bottom layer of the operating system, but through native methods. The Unsafe class provides hardware-level atomic operations, mainly providing the following functions:

1. The memory can be allocated and released through the Unsafe class;

The three local methods allocateMemory, reallocateMemory, and freeMemory provided in the class are used to allocate memory, expand memory and release memory, corresponding to the three methods in C language.

public native long allocateMemory(long l);
public native long reallocateMemory(long l, long l1);
public native void freeMemory(long l);

2. You can locate the memory location of a field of the object, and you can also modify the field value of the object, even if it is private;

Positioning of fields:

The positioning of the fields of objects in JAVA may be achieved by the staticFieldOffset method, which returns the memory address offset of the given field, which is unique and fixed for the given filed.

The getIntVolatile method obtains the value of the integer field corresponding to the offset offset address in the object, and supports volatile load semantics.

The getLong method gets the value of the long field corresponding to the offset address in the object

Array element positioning:

There are many constants ending with BASE_OFFSET in the Unsafe class, such as ARRAY_INT_BASE_OFFSET, ARRAY_BYTE_BASE_OFFSET, etc. These constant values ​​are obtained through the arrayBaseOffset method. The arrayBaseOffset method is a native method that gets the offset address of the first element of the array. There are also many constants ending with INDEX_SCALE in the Unsafe class, such as ARRAY_INT_INDEX_SCALE, ARRAY_BYTE_INDEX_SCALE, etc. These constant values ​​are obtained through the arrayIndexScale method. The arrayIndexScale method is also a native method that gets the conversion factor of the array, which is the incremental address of the elements in the array. Use arrayBaseOffset with arrayIndexScale to locate each element in an array in memory.

Arrays, like other objects in Java, have an object header, which is stored in front of the actual data. The length of this header can be obtained by the unsafe.arrayBaseOffset(T[].class) method, where T is the type of the array element. The size of the array element can be obtained through the unsafe.arrayIndexScale(T[].class) method. This means that to access the Nth element of type T, your offset offset should be arrayOffset+N*arrayScale.

public final class Unsafe {
    public static final int ARRAY_INT_BASE_OFFSET;
    public static final int ARRAY_INT_INDEX_SCALE;

    public native long staticFieldOffset(Field field);
    public native int getIntVolatile(Object obj, long l);
    public native long getLong(Object obj, long l);
    public native int arrayBaseOffset(Class class1);
    public native int arrayIndexScale(Class class1);

    static
    {
        ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset([I);
        ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale([I);
    }
}

3. Suspend and resume

Suspending a thread is implemented by the park method. After calling park, the thread will be blocked until a timeout or interruption occurs. unpark can terminate a suspended thread and bring it back to normal. The thread suspension operation in the entire concurrency framework is encapsulated in the LockSupport class. There are various versions of the pack method in the LockSupport class, but the Unsafe.park() method is eventually called.

 

public class LockSupport {
    public static void unpark(Thread thread) {
        if (thread != null)
            unsafe.unpark(thread);
    }

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(false, 0L);
        setBlocker(t, null);
    }

    public static void parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            unsafe.park (false, nanos);
            setBlocker(t, null);
        }
    }

    public static void parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(true, deadline);
        setBlocker(t, null);
    }

    public static void park() {
        unsafe.park(false, 0L);
    }

    public static void parkNanos(long nanos) {
        if (nanos > 0)
            unsafe.park (false, nanos);
    }

    public static void parkUntil(long deadline) {
        unsafe.park(true, deadline);
    }
}

 

4. CAS operation

It is implemented through the compareAndSwapXXX method

 

/**
* Compare the value in the memory location at offset of obj with the expected value, and update if they are the same. This update is uninterrupted.
*
* @param obj the object that needs to be updated
* @param offset The offset of the integer field in obj
* @param expect expects the value that exists in the field
* @param update If the expected value expect is the same as the current value of field, set the value of filed to this new value
* @return returns true if the field's value has been changed
*/
public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);

 

CAS operation has 3 operands, memory value M, expected value E, new value U, if M==E, then change the memory value to B, otherwise do nothing.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324982218&siteId=291194637