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:
Method | purpose |
---|---|
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:
Method | purpose |
---|---|
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();
}
}