Concurrent Programming-07.Atominc Atom Package and Unsafe Magic Classes

Keywords: Java jvm Multithreading Concurrent Programming

1. Atominc Atom Package

There are 12 classes in the Atomic package, and there are four ways to update atoms: the basic type of atomic update, the array, the reference, and the field. The classes in the Atomic package are basically wrapper classes implemented using Unsafe.

Basic Classes: AtomicInteger, AtomicLong, AtomicBoolean

Reference types: AtomicReference, ABA instance of AtomicReference, AtomicStampedRerence, AtomicMarkableReference

Array type: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray

Attribute Atomic Modifier (Updater): AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater

What is an offset?

When we use CAS to modify an object's attribute value, we first need to know the location of the attribute in the object's memory space. We must know the offset of the object, and this attribute can be found directly by the offset.

CAS lock-free concurrency algorithm

1. Classes of basic types of atomic updates

AtomicBoolean: Atomic Update Boolean Type

AtomicInteger: Atomic renewal integer.

AtomicLong: Atom updates a long integer.

For AtomicInteger, for example, some API s are as follows:

Methodpurpose
int addAndGet(int delta)Atomically adds the value entered to the value in the instance (value in AtomicInteger) and returns the result
boolean compareAndSet(int expect, int update)If the value entered equals the expected value, set it atomically to the value entered
int getAndIncrement()Atomically add the current value to 1, note that the return here is augmentation
void lazySet(int newValue)Finally set to newValue, setting a value with lazySet may cause other threads to read the old value for a short period of time
int getAndSet(int newValue)Atomically set to the value of newValue and return to the old

Partial Source Analysis:

// Unsafe class
/**
 * Most API s are basically designed this way
 * @param var1 Object AtomicInteger @param var2 offset
 * @param var4 Value to add
 */
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5; // oldValue old value
    do {
        var5 = this.getIntVolatile(var1, var2); // Read the value of AtomicInteger
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

2. Atomic Update Array Class

AtomicIntegerArray: Atomic updates elements in an integer array

AtomicLongArray: Atoms update elements in long integer arrays

AtomicReferenceArray: Atomic update of elements in reference type array

Take AtomicIntegerArray as an example, and some API s are as follows:

Methodpurpose
int addAndGet(int i, int delta)Atomically adds the input value to the element of index i in the array
boolean compareAndSet(int i, int expect, int update)Atomically set the element at array position i to an update value if the current value equals the expected value

Note: This array is not the original but a shallow copy (calling the clone method)

public AtomicIntegerArray(int[] array) {
    // Visibility guaranteed by final field guarantees
    this.array = array.clone();
}

3. Atomic Update Reference Type

AtomicReference: Atomic update reference type

AtomicReferenceFieldUpdater: Attributes (fields) in an atomic update reference type

AtomicMarkableReference: Atomic update reference type with marker bit

4. Atomic Update Field Class

AtomicIntegerFieldUpdater: Updater for atom update integer fields

AtomicLongFieldUpdater: Atomic Update Updater for Long Integer Fields

AtomicStampedReference: Atomic update of reference type with version number (solves CAS problem)

AtomicStampedReference associates integer values with references and can be used to update data and version numbers for atoms to solve ABA problems that may arise when atoms are updated using CAS. The compareAndSet method has two parameters and four parameters, which pass the corresponding version number and address operations after each modification.

public class AtomicStampedReferenceRunner {

    private static AtomicStampedReference<Integer> atomicStampedRef =
            new AtomicStampedReference<>(1, 0);

    public static void main(String[] args){
        Thread main = new Thread(() -> {
            int stamp = atomicStampedRef.getStamp(); //Get the current identity
            System.out.println("Operational Threads" + Thread.currentThread()+ "stamp = "+stamp + ",initial value a = " + atomicStampedRef.getReference());
            try {
                Thread.sleep(3000); //Wait 3 seconds for interfering threads to execute
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean isCASSuccess = atomicStampedRef.compareAndSet(1,2,stamp,stamp +1);  //ExpctedReference did not change at this time, but stamp has been modified, so CAS failed
            System.out.println("Operational Threads" + Thread.currentThread() + "stamp = "+stamp + ",CAS Operation Result: " + isCASSuccess);
        },"Main Operation Thread");

        Thread other = new Thread(() -> {
            int stamp = atomicStampedRef.getStamp();
            atomicStampedRef.compareAndSet(1,2,stamp,stamp+1);
            System.out.println("Operational Threads" + Thread.currentThread() + "stamp = "+atomicStampedRef.getStamp() +",[increment] ,value a = "+ atomicStampedRef.getReference());
            stamp = atomicStampedRef.getStamp();
            atomicStampedRef.compareAndSet(2,1,stamp,stamp+1);
            System.out.println("Operational Threads" + Thread.currentThread() + "stamp = "+atomicStampedRef.getStamp() +",[decrement] ,value a = "+ atomicStampedRef.getReference());
        },"Disturb Threads");

        main.start();
        LockSupport.parkNanos(1000000);
        other.start();
    }
}
Run Results
------------------------------------------------------------
Operational Threads Thread[Main Operation Thread,5,main]stamp = 0,initial value a = 1
 Operational Threads Thread[Disturb Threads,5,main]stamp = 1,[increment] ,value a = 2
 Operational Threads Thread[Disturb Threads,5,main]stamp = 2,[decrement] ,value a = 1
 Operational Threads Thread[Main Operation Thread,5,main]stamp = 0,CAS Operation Result: false

2. Magic Unsafe

A class located under the sun.misc package, mainly provides some methods to perform low-level, unsafe operations, such as direct access to system memory resources, self-management of memory resources, etc. Unsafe must be used with caution, excessive and incorrect use of Unsafe classes can make programs more likely to fail and become less secure.

Unsafe class partial source:

private static final Unsafe theUnsafe;
// Private Construction
private Unsafe() {
}
// Singleton mode
@CallerSensitive
public static Unsafe getUnsafe() {
    Class var0 = Reflection.getCallerClass();
    // Legally only when boot class loader loads, otherwise throw an exception
    if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
        throw new SecurityException("Unsafe");
    } else {
        return theUnsafe;
    }
}

static {
    // Some code has been omitted
    theUnsafe = new Unsafe();
}

Methods to get UnSafe instances

Method 1:

1. From the restrictions of using the getUnsafe method, append the jar package path of the class A that calls the Unsafe related method to the default bootstrap path through the Java command line command-Xbootclasspath/a, so that A is loaded by the bootstrap loader, thus securing the Unsafe instance through the Unsafe.getUnsafe method.

java @ Xbootclasspath/a:${path} //where path is the jar package path of the class that calls the Unsafe related method

Method 2:

Get the Unsafe singleton object by reflection, which is usually written as a tool class

public class UnsafeInstance {
    public static Unsafe reflectGetUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        int j=1;
        reflectGetUnsafe().loadFence();
        int i= 0;
    }
}

Unsafe Purpose Classification

1. Memory operations

// Allocate memory
public native long allocateMemory(long var1);
// Expanded memory
public native long reallocateMemory(long var1, long var3);
// Set a value in a given memory block
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);
}
// Memory Copy
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);
}
// Release memory
public native void freeMemory(long var1);

// Gets the given address value, ignoring access restrictions for modifiers. Similar operations include getInt, getDouble, getLong, getChar, and so on 
public native Object getObject(Object o, long offset); 
// Set values for a given address, ignoring access restrictions for modifiers, and similar operations: putInt,putDouble, putLong, putChar, and so on 
public native void putObject(Object o, long offset, Object x); 
// Gets the value of a given address byte type
public native byte getByte(long address); 
//Set a value of byte type for a given address (the result of this method is deterministic if and only if the memory address is allocateMemory allocated) 
public native void putByte(long address, byte x);

Why use out-of-heap memory?

  • Optimize garbage collection. Out-of-heap memory is managed directly by the operating system and is not controlled by the JVM. Using out-of-heap memory can reduce heap memory pressure, thereby reducing the impact of garbage collection pauses on applications when GC is in progress.
  • Improving the performance of program I/O operations. Data copy operations from in-heap memory to out-of-heap memory usually occur during I/O communication. Storing in out-of-heap memory is recommended for temporary data that requires frequent inter-memory data copies and has a shorter life cycle.

Note: Out-of-heap memory is not controlled by JVM and must be freed when used up

Typical applications

DirectByteBuffer is an important class used by Java to implement out-of-heap memory through which we can create, use, and destroy out-of-heap memory.

DirectByteBuffer(int cap) {                   // package-private
    super(-1, 0, cap, cap);
    boolean pa = VM.isDirectMemoryPageAligned();
    int ps = Bits.pageSize();
    long size = Math.max(1L, (long)cap + (pa ? ps : 0));
    // Reserve total allocated memory (allocated by page) and actual memory size
    Bits.reserveMemory(size, cap);

    long base = 0;
    try {
        // Allocate out-of-heap memory and return the base address of out-of-heap memory
        base = unsafe.allocateMemory(size);
    } catch (OutOfMemoryError x) {
        Bits.unreserveMemory(size, cap);
        throw x;
    }
    // Memory Initialization
    unsafe.setMemory(base, size, (byte) 0);
    if (pa && (base % ps != 0)) {
        // Round up to page boundary
        address = base + ps - (base & (ps - 1));
    } else {
        address = base;
    }
    // Build Cleaner objects to track garbage collection of DirectByteBuffer objects
    // To allow out-of-heap memory to be freed when DirectByteBuffer is garbage collected
    cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
    att = null;
}
public static void main(String[] args) {
    Unsafe unsafe = UnsafeInstance.reflectGetUnsafe();
    long oneHundred = 12012341234567891234L;
    byte size = 8;
    // Call allocateMemory to allocate memory
    long memoryAddress = unsafe.allocateMemory(size);
    System.out.println("address:"+memoryAddress);
    // Write to memory
    unsafe.putAddress(memoryAddress, oneHundred);
    // Read data in memory
    long readValue = unsafe.getAddress(memoryAddress);

    System.out.println("value:" + readValue);
	// Release memory
    unsafe.freeMemory(memoryAddress);
}
Run Results
--------------------------------------
address:56555456
value:12012341234567891234L

2. CAS correlation

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); 
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);

3. Thread Scheduling

//Unblock Threads 
public native void unpark(Object thread); 
//Blocking Threads 
public native void park(boolean isAbsolute, long time); 
//Obtain object locks (re-lockable) 
@Deprecated 
public native void monitorEnter(Object o); 
//Release Object Lock 
@Deprecated 
public native void monitorExit(Object o); 
//Attempt to acquire object lock 
@Deprecated 
public native boolean tryMonitorEnter(Object o);

Typical applications

1.LockSupport.park() and LockSupport.unpark() implement thread blocking and waking

2. Cross-method unlocking

public class ObjectMonitorRunner {
    static Object object = new Object();
    // Get Unsafe Object
    static Unsafe unsafe = UnsafeInstance.reflectGetUnsafe();
    public void method1(){
        unsafe.monitorEnter(object); // Locking
    }

    public void method2(){
        unsafe.monitorExit(object); // Release lock
    }
}

4. Memory barrier

//Memory barrier, prevents the load operation from reordering. The load operation before the barrier cannot be reordered to the barrier, and the load operation behind the barrier cannot be reordered to the front of the barrier. 
public native void loadFence(); 
//store operations cannot be reordered to the front of the barrier. store operations behind the barrier cannot be reordered to the front of the barrier.
public native void storeFence(); 
//Memory barrier, prevent re load, store operations from reordering 
public native void fullFence();

Attached UNsafe source:

package sun.misc;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

public final class Unsafe {
    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();

    private Unsafe() {
    }

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

    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);

    public native boolean getBoolean(Object var1, long var2);

    public native void putBoolean(Object var1, long var2, boolean var4);

    public native byte getByte(Object var1, long var2);

    public native void putByte(Object var1, long var2, byte var4);

    public native short getShort(Object var1, long var2);

    public native void putShort(Object var1, long var2, short var4);

    public native char getChar(Object var1, long var2);

    public native void putChar(Object var1, long var2, char var4);

    public native long getLong(Object var1, long var2);

    public native void putLong(Object var1, long var2, long var4);

    public native float getFloat(Object var1, long var2);

    public native void putFloat(Object var1, long var2, float var4);

    public native double getDouble(Object var1, long var2);

    public native void putDouble(Object var1, long var2, double var4);

    /** @deprecated */
    @Deprecated
    public int getInt(Object var1, int var2) {
        return this.getInt(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putInt(Object var1, int var2, int var3) {
        this.putInt(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public Object getObject(Object var1, int var2) {
        return this.getObject(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putObject(Object var1, int var2, Object var3) {
        this.putObject(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public boolean getBoolean(Object var1, int var2) {
        return this.getBoolean(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putBoolean(Object var1, int var2, boolean var3) {
        this.putBoolean(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public byte getByte(Object var1, int var2) {
        return this.getByte(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putByte(Object var1, int var2, byte var3) {
        this.putByte(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public short getShort(Object var1, int var2) {
        return this.getShort(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putShort(Object var1, int var2, short var3) {
        this.putShort(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public char getChar(Object var1, int var2) {
        return this.getChar(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putChar(Object var1, int var2, char var3) {
        this.putChar(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public long getLong(Object var1, int var2) {
        return this.getLong(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putLong(Object var1, int var2, long var3) {
        this.putLong(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public float getFloat(Object var1, int var2) {
        return this.getFloat(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putFloat(Object var1, int var2, float var3) {
        this.putFloat(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public double getDouble(Object var1, int var2) {
        return this.getDouble(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putDouble(Object var1, int var2, double var3) {
        this.putDouble(var1, (long)var2, var3);
    }

    public native byte getByte(long var1);

    public native void putByte(long var1, byte var3);

    public native short getShort(long var1);

    public native void putShort(long var1, short var3);

    public native char getChar(long var1);

    public native void putChar(long var1, char var3);

    public native int getInt(long var1);

    public native void putInt(long var1, int var3);

    public native long getLong(long var1);

    public native void putLong(long var1, long var3);

    public native float getFloat(long var1);

    public native void putFloat(long var1, float var3);

    public native double getDouble(long var1);

    public native void putDouble(long var1, double var3);

    public native long getAddress(long var1);

    public native void putAddress(long var1, long var3);

    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);

    /** @deprecated */
    @Deprecated
    public int fieldOffset(Field var1) {
        return Modifier.isStatic(var1.getModifiers()) ? (int)this.staticFieldOffset(var1) : (int)this.objectFieldOffset(var1);
    }

    /** @deprecated */
    @Deprecated
    public Object staticFieldBase(Class<?> var1) {
        Field[] var2 = var1.getDeclaredFields();

        for(int var3 = 0; var3 < var2.length; ++var3) {
            if (Modifier.isStatic(var2[var3].getModifiers())) {
                return this.staticFieldBase(var2[var3]);
            }
        }

        return null;
    }

    public native long staticFieldOffset(Field var1);

    public native long objectFieldOffset(Field var1);

    public native Object staticFieldBase(Field var1);

    public native boolean shouldBeInitialized(Class<?> var1);

    public native void ensureClassInitialized(Class<?> var1);

    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<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);

    public native Object allocateInstance(Class<?> var1) throws InstantiationException;

    /** @deprecated */
    @Deprecated
    public native void monitorEnter(Object var1);

    /** @deprecated */
    @Deprecated
    public native void monitorExit(Object var1);

    /** @deprecated */
    @Deprecated
    public native boolean tryMonitorEnter(Object var1);

    public native void throwException(Throwable var1);

    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

    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);

    public native boolean getBooleanVolatile(Object var1, long var2);

    public native void putBooleanVolatile(Object var1, long var2, boolean var4);

    public native byte getByteVolatile(Object var1, long var2);

    public native void putByteVolatile(Object var1, long var2, byte var4);

    public native short getShortVolatile(Object var1, long var2);

    public native void putShortVolatile(Object var1, long var2, short var4);

    public native char getCharVolatile(Object var1, long var2);

    public native void putCharVolatile(Object var1, long var2, char var4);

    public native long getLongVolatile(Object var1, long var2);

    public native void putLongVolatile(Object var1, long var2, long var4);

    public native float getFloatVolatile(Object var1, long var2);

    public native void putFloatVolatile(Object var1, long var2, float var4);

    public native double getDoubleVolatile(Object var1, long var2);

    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);

    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;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

    public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

        return var6;
    }

    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;
    }

    public final long getAndSetLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var4));

        return var6;
    }

    public final Object getAndSetObject(Object var1, long var2, Object var4) {
        Object var5;
        do {
            var5 = this.getObjectVolatile(var1, var2);
        } while(!this.compareAndSwapObject(var1, var2, var5, var4));

        return var5;
    }

    public native void loadFence();

    public native void storeFence();

    public native void fullFence();

    private static void throwIllegalAccessError() {
        throw new IllegalAccessError();
    }

    static {
        registerNatives();
        Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
        theUnsafe = new Unsafe();
        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();
    }
}

_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();
}
}

Posted by Cragsterboy on Thu, 23 Sep 2021 09:10:56 -0700