并发编程-07.Atominc 原子包及 Unsafe 魔法类

一、Atominc 原子包

在 Atomic 包中有12个类,四种原子更新方式,分别是原子更新基本类型、数组、引用和字段。Atomic 包里的类基本都是使用 Unsafe 实现的包装类。

基本类: AtomicInteger、AtomicLong、AtomicBoolean

引用类型: AtomicReference、AtomicReference的ABA实例、AtomicStampedRerence、AtomicMarkableReference

数组类型: AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

属性原子修改器(Updater): AtomicIntegerFieldUpdater、 AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

什么是偏移量?

我们使用 CAS 修改某个对象的属性值是,首先需要知道该属性在对象的内存空间的那个位置,就必须要知道对象的偏移量,通过偏移量就能直接找到这个属性。

(img-inBnT55R-1632414789813)(C:\Users\zhe\AppData\Roaming\Typora\typora-user-images\image-20210923001623751.png)]

CAS无锁并发算法

1、原子更新基本类型类

AtomicBoolean: 原子更新布尔类型

AtomicInteger: 原子更新整型。

AtomicLong: 原子更新长整型。

以 AtomicInteger 为例部分 API 如下:

方法用途
int addAndGet(int delta)以原子方式将输入的数值与实例中的值 (AtomicInteger里的value)相加,并返回结果
boolean compareAndSet(int expect, int update)如果输入的数值等于预期值,则以原子方式将该值设置为输入的值
int getAndIncrement()以原子方式将当前值加1,注意:这里返回的是自增
void lazySet(int newValue)最终设置成 newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值
int getAndSet(int newValue)以原子方式设置为newValue的值,并返回旧

部分源码分析:

// Unsafe类
/**
 * 大多API基本都是如此设计
 * @param var1 对象AtomicInteger  @param var2 偏移量
 * @param var4 需要加的数值
 */
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5; // oldValue 旧值
    do {
        var5 = this.getIntVolatile(var1, var2); // 读AtomicInteger的value值
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

2、原子更新数组类

AtomicIntegerArray:原子更新整型数组里的元素

AtomicLongArray:原子更新长整型数组里的元素

AtomicReferenceArray:原子更新引用类型数组里的元素

以 AtomicIntegerArray为例部分 API 如下:

方法用途
int addAndGet(int i, int delta)以原子方式将输入值与数组中索引 i 的元素相加
boolean compareAndSet(int i, int expect, int update)如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值

注意: 此数组并非原数组,而是浅拷贝(调用了 clone 方法)的一份数组

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

3、原子更新引用类型

AtomicReference:原子更新引用类型

AtomicReferenceFieldUpdater:原子更新引用类型里的属性(字段)

AtomicMarkableReference:原子更新带有标记位的引用类型

4、原子更新字段类

AtomicIntegerFieldUpdater:原子更新整型的字段的更新器

AtomicLongFieldUpdater:原子更新长整型字段的更新器

AtomicStampedReference:原子更新带有版本号的引用类型(可解决 CAS 问题)

AtomicStampedReference 将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用 CAS 进行原子更新时,可能出现的ABA问题。compareAndSet方法有两个参数和四个参数两种,四个参数的会传递对应的版本号,版本号在每次修改后会进行地址操作。

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(); //获取当前标识别
            System.out.println("操作线程" + Thread.currentThread()+ "stamp = "+stamp + ",初始值 a = " + atomicStampedRef.getReference());
            try {
                Thread.sleep(3000); //等待3秒 ,以便让干扰线程执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean isCASSuccess = atomicStampedRef.compareAndSet(1,2,stamp,stamp +1);  //此时expectedReference未发生改变,但是stamp已经被修改了,所以CAS失败
            System.out.println("操作线程" + Thread.currentThread() + "stamp = "+stamp + ",CAS操作结果: " + isCASSuccess);
        },"主操作线程");

        Thread other = new Thread(() -> {
            int stamp = atomicStampedRef.getStamp();
            atomicStampedRef.compareAndSet(1,2,stamp,stamp+1);
            System.out.println("操作线程" + Thread.currentThread() + "stamp = "+atomicStampedRef.getStamp() +",【increment】 ,值 a = "+ atomicStampedRef.getReference());
            stamp = atomicStampedRef.getStamp();
            atomicStampedRef.compareAndSet(2,1,stamp,stamp+1);
            System.out.println("操作线程" + Thread.currentThread() + "stamp = "+atomicStampedRef.getStamp() +",【decrement】 ,值 a = "+ atomicStampedRef.getReference());
        },"干扰线程");

        main.start();
        LockSupport.parkNanos(1000000);
        other.start();
    }
}
运行结果
------------------------------------------------------------
操作线程Thread[主操作线程,5,main]stamp = 0,初始值 a = 1
操作线程Thread[干扰线程,5,main]stamp = 1,【increment】 ,值 a = 2
操作线程Thread[干扰线程,5,main]stamp = 2,【decrement】 ,值 a = 1
操作线程Thread[主操作线程,5,main]stamp = 0,CAS操作结果: false

二、魔法类 Unsafe

位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源自主管理内存资源等。Unsafe 使用一定要谨慎,过度、不正确使用 Unsafe 类会使得程序出错的概率变大,变得不再安全。

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 实例的方法

方法一:

1、从getUnsafe方法的使用限制条件出发,通过Java命令行命令-Xbootclasspath/a把调用Unsafe相关方法的类A所在jar包路径追加到默认的bootstrap路径中,使得A被 引导类加载器加载,从而通过Unsafe.getUnsafe方法安全的获取Unsafe实例。

java ­Xbootclasspath/a:${path} // 其中path为调用Unsafe相关方法的类所在jar包路径

方法二:

通过反射获取单例对象 theUnsafe,通常可以把它写成一个工具类

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 用途分类

1、内存操作
// 分配内存
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);

// 获取给定地址值,忽略修饰限定符的访问限制。与此类似操作还有: getInt, getDouble,getLong,getChar等 
public native Object getObject(Object o, long offset); 
// 为给定地址设置值,忽略修饰限定符的访问限制,与此类似操作还有: putInt,putDouble,putLong,putChar等 
public native void putObject(Object o, long offset, Object x); 
// 获取给定地址byte类型的值
public native byte getByte(long address); 
//为给定地址设置byte类型的值(当且仅当该内存地址为 allocateMemory 分配时,此方法结果才是确定的) 
public native void putByte(long address, byte x);

为什么要使用堆外内存?

  • 优化垃圾回收,堆外内存直接由操作系统管理,不受 JVM 控制,使用堆外内存可以减小堆内存压力,从而减少 GC 时减少垃圾回收停顿对应用的影响。
  • 提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到堆外内存

注意: 堆外内存不受 JVM 控制,用完一定要进行释放

典型应用

DirectByteBuffer是Java用于实现堆外内存的一个重要类,我们可以通过该类实现堆外内存的创建、使用和销毁。

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));
    // 保留总分配内存(按页分配)的大小和实际内存的大小
    Bits.reserveMemory(size, cap);

    long base = 0;
    try {
        // 分配堆外内存,并返回堆外内存的基地址
        base = unsafe.allocateMemory(size);
    } catch (OutOfMemoryError x) {
        Bits.unreserveMemory(size, cap);
        throw x;
    }
    // 内存初始化
    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;
    }
    // 构建Cleaner对象用于跟踪DirectByteBuffer对象的垃圾回收
    // 以实现当DirectByteBuffer被垃圾回收时,堆外内存也会被释放
    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;
    // 调用allocateMemory分配内存
    long memoryAddress = unsafe.allocateMemory(size);
    System.out.println("address:"+memoryAddress);
    // 写入到内存中
    unsafe.putAddress(memoryAddress, oneHundred);
    // 内存中读取数据
    long readValue = unsafe.getAddress(memoryAddress);

    System.out.println("value:" + readValue);
	// 释放内存
    unsafe.freeMemory(memoryAddress);
}
运行结果
--------------------------------------
address:56555456
value:12012341234567891234L
2、CAS相关
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、线程调度
//取消阻塞线程 
public native void unpark(Object thread); 
//阻塞线程 
public native void park(boolean isAbsolute, long time); 
//获得对象锁(可重入锁) 
@Deprecated 
public native void monitorEnter(Object o); 
//释放对象锁 
@Deprecated 
public native void monitorExit(Object o); 
//尝试获取对象锁 
@Deprecated 
public native boolean tryMonitorEnter(Object o);

典型应用

1.LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒

2.跨方法加解锁

public class ObjectMonitorRunner {
    static Object object = new Object();
    // 获取Unsafe对象
    static Unsafe unsafe = UnsafeInstance.reflectGetUnsafe();
    public void method1(){
        unsafe.monitorEnter(object); // 加锁
    }

    public void method2(){
        unsafe.monitorExit(object); // 释放锁
    }
}
4、内存屏障
//内存屏障,禁止load操作重排序。屏障前的load操作不能被重排序到屏障后,屏障后的load操作不能被重排序到屏障前 
public native void loadFence(); 
//内存屏障,禁止store操作重排序。屏障前的store操作不能被重排序到屏障后,屏障后的store操作不能被重排序到屏障前
public native void storeFence(); 
//内存屏障,禁止load、store操作重排序 
public native void fullFence();

附 UNsafe 源码:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值