diff --git a/week_02/15/AtomicInteger-015.md b/week_02/15/AtomicInteger-015.md new file mode 100644 index 0000000000000000000000000000000000000000..8686fe8b228114aa70639cf7817cfb402ff52275 --- /dev/null +++ b/week_02/15/AtomicInteger-015.md @@ -0,0 +1,166 @@ +### [Java 8] AtomicInteger + +完全利用Unsafe的CAS操作封装了int值的读取-修改-更新原子操作 + +#### 静态初始化相关 +``` java +// 因为在rt.jar包中,由启动类加载器加载,因此可以直接由getUnsafe()获取到Unsafe实例 +private static final Unsafe unsafe = Unsafe.getUnsafe(); +// 记录实例字段value在AtomicInteger实例中的地址偏移,在静态构造器中初始化,用于CAS操作 +private static final long valueOffset; + +static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicInteger.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } +} +``` + + +#### 对象构造相关 +``` java +// 实际的int变量值(有volatile读/写语义) +private volatile int value; + +public AtomicInteger(int initialValue) { + value = initialValue; +} + +public AtomicInteger() { +} +``` + + +#### 各种读写方法 +``` java +// 获取int值(volatile读语义) +public final int get() { + return value; +} + +// 设置int值(volatile写语义) +public final void set(int newValue) { + value = newValue; +} + +// 设置int值(lazy写语义),在一些value更新不需要立即可见的场景下可以提升性能,因为putOrderedInt并没有使用相对昂贵的StoreLoad语义屏障。但最终可见还是要靠value的volatile写触发 +public final void lazySet(int newValue) { + unsafe.putOrderedInt(this, valueOffset, newValue); +} + +// 设置新的int值并返回替换的int值 +public final int getAndSet(int newValue) { + return unsafe.getAndSetInt(this, valueOffset, newValue); +} + +// 原子比较-替换操作,如果value值为expect则用update替换value值并返回true(替换成功),否则不替换并返回false(替换失败) +public final boolean compareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); +} + +// 和compareAndSet一样,可能之前的版本不一样吧 +public final boolean weakCompareAndSet(int expect, int update) { + return unsafe.compareAndSwapInt(this, valueOffset, expect, update); +} + +// 原子value++ +public final int getAndIncrement() { + return unsafe.getAndAddInt(this, valueOffset, 1); +} + +// 原子value-- +public final int getAndDecrement() { + return unsafe.getAndAddInt(this, valueOffset, -1); +} + +// 原子value+delta(返回替换的value值) +public final int getAndAdd(int delta) { + return unsafe.getAndAddInt(this, valueOffset, delta); +} + +// 原子++value +public final int incrementAndGet() { + return unsafe.getAndAddInt(this, valueOffset, 1) + 1; +} + +// 原子--value +public final int decrementAndGet() { + return unsafe.getAndAddInt(this, valueOffset, -1) - 1; +} + +// 原子value+delta(返回替换后的value值) +public final int addAndGet(int delta) { + return unsafe.getAndAddInt(this, valueOffset, delta) + delta; +} + +// 原子value+updateFunction(value),返回替换的value值 +public final int getAndUpdate(IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(); + next = updateFunction.applyAsInt(prev); + // 由于可能会有多个线程竞争修改,因此循环可能执行多次,故需要保证updateFunction是没有副作用的纯函数 + } while (!compareAndSet(prev, next)); + return prev; +} + +// 原子value+updateFunction(value),返回替换后的value值 +public final int updateAndGet(IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(); + next = updateFunction.applyAsInt(prev); + // 由于可能会有多个线程竞争修改,因此循环可能执行多次,故需要保证updateFunction是没有副作用的纯函数 + } while (!compareAndSet(prev, next)); + return next; +} + +// 原子value+accumulatorFunction(value, x),返回替换的value值 +public final int getAndAccumulate(int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(); + next = accumulatorFunction.applyAsInt(prev, x); + // 由于可能会有多个线程竞争修改,因此循环可能执行多次,故需要保证accumulatorFunction是没有副作用的纯函数 + } while (!compareAndSet(prev, next)); + return prev; +} + +// 原子value+accumulatorFunction(value, x),返回替换后的value值 +public final int accumulateAndGet(int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(); + next = accumulatorFunction.applyAsInt(prev, x); + // 由于可能会有多个线程竞争修改,因此循环可能执行多次,故需要保证accumulatorFunction是没有副作用的纯函数 + } while (!compareAndSet(prev, next)); + return next; +} +``` + + +#### 其他Object及Number方法 +``` java +public String toString() { + return Integer.toString(get()); +} + +public int intValue() { + return get(); +} + +public long longValue() { + return (long)get(); +} + +public float floatValue() { + return (float)get(); +} + +public double doubleValue() { + return (double)get(); +} +``` diff --git a/week_02/15/Unsafe-015.md b/week_02/15/Unsafe-015.md new file mode 100644 index 0000000000000000000000000000000000000000..5a085d61d3fbffdb7550740a34bf87f5901029c6 --- /dev/null +++ b/week_02/15/Unsafe-015.md @@ -0,0 +1,509 @@ +### [Java 8] Unsafe + +提供低级别、不安全操作的 native 方法,例如手动管理内存等。基本上是通过JNI访问本地C++库 + +#### 构造相关 +``` java +// 对应C++库中的Java_sun_misc_Unsafe_registerNatives函数,这是JNI名称映射规则。在这个函数内注册了所有Unsafe内方法对应的原生函数,通过这个注册,这些原生函数就不需要按JNI名称映射规则加那一坨前缀 +private static native void registerNatives(); + +static { + // 注册C++原生函数 + registerNatives(); + // 注册到反射过滤方法表中,反射时找不到getUnsafe方法 + sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); +} + +// 单例 +private Unsafe() {} + +private static final Unsafe theUnsafe = new Unsafe(); + +@CallerSensitive +public static Unsafe getUnsafe() { + // 配合@CallerSensitive注解找到最源头的调用者所在类 + Class caller = Reflection.getCallerClass(); + // 判断调用者所在类是否由启动类加载器加载 + if (!VM.isSystemDomainLoader(caller.getClassLoader())) + // 如果不是启动类加载器加载,则抛出异常,以此限制Unsafe的使用范围 + // 但可以通过反射theUnsafe绕过 + throw new SecurityException("Unsafe"); + return theUnsafe; +} +``` + + +#### 内存操作 +``` java +// 由变量o地址偏移offset取int值;如果o为null,则offset为绝对内存地址 +public native int getInt(Object o, long offset); + +// 由变量o地址偏移offset设置int值;如果o为null,则offset为绝对内存地址 +public native void putInt(Object o, long offset, int x); + +// 以下同上两个方法 +public native Object getObject(Object o, long offset); + +public native void putObject(Object o, long offset, Object x); + +public native boolean getBoolean(Object o, long offset); + +public native void putBoolean(Object o, long offset, boolean x); + +public native byte getByte(Object o, long offset); + +public native void putByte(Object o, long offset, byte x); + +public native short getShort(Object o, long offset); + +public native void putShort(Object o, long offset, short x); + +public native char getChar(Object o, long offset); + +public native void putChar(Object o, long offset, char x); + +public native long getLong(Object o, long offset); + +public native void putLong(Object o, long offset, long x); + +public native float getFloat(Object o, long offset); + +public native void putFloat(Object o, long offset, float x); + +public native double getDouble(Object o, long offset); + +public native void putDouble(Object o, long offset, double x); + +// 由地址address取byte值 +public native byte getByte(long address); + +// 由地址address设置byte值 +public native void putByte(long address, byte x); + +// 以下同上两个方法 +public native short getShort(long address); + +public native void putShort(long address, short x); + +public native char getChar(long address); + +public native void putChar(long address, char x); + +public native int getInt(long address); + +public native void putInt(long address, int x); + +public native long getLong(long address); + +public native void putLong(long address, long x); + +public native float getFloat(long address); + +public native void putFloat(long address, float x); + +public native double getDouble(long address); + +public native void putDouble(long address, double x); + +// 以下两个方法同 getLong(long address) 和 putLong(long address, long x) 的区别在于指针的大小不一定是8个字节,具体大小由C++编译器决定。针对指针的方法只读/写指针大小的字节,而针对long的方法会读/写整8个字节 +// 由地址address获取指针 +public native long getAddress(long address); + +// 由地址address设置指针 +public native void putAddress(long address, long x); + +// 分配一块bytes字节大小的内存,这块内存属于堆外内存,不由JVM管控 +public native long allocateMemory(long bytes); + +// 扩充起始地址为address内存块到bytes字节大小 +public native long reallocateMemory(long address, long bytes); + +// 将由变量o地址偏移offset的地址起始大小为bytes字节的内存块每字节都设置为value;如果o为null,则offset为起始地址 +public native void setMemory(Object o, long offset, long bytes, byte value); + +// 将address地址起始大小为bytes字节的内存块每字节都设置为value +public void setMemory(long address, long bytes, byte value) { + setMemory(null, address, bytes, value); +} + +// 将由变量srcBase地址偏移srcOffset的地址起始大小为bytes的内存块拷贝到由变量destBase地址偏移destOffset的起始地址;如果srcBase或destBase为null,则相应srcOffset或destOffset为起始地址 +public native void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes); + +// 将srcAddress地址起始大小为bytes的内存块拷贝到destAddress起始地址 +public void copyMemory(long srcAddress, long destAddress, long bytes) { + copyMemory(null, srcAddress, null, destAddress, bytes); +} + +// 释放内存块 +public native void freeMemory(long address); +``` + + +#### 类型及对象操作 +``` java +// 获取给定静态字段相对类型地址的偏移量 +public native long staticFieldOffset(Field f); + +// 获取静态字段所属的Class对象 +public native Object staticFieldBase(Field f); + +// 获取给定对象实例字段相对对象地址的偏移量 +public native long objectFieldOffset(Field f); + +// 获取数组中第一个元素相对数组地址的偏移量 +public native int arrayBaseOffset(Class arrayClass); + +// 贴心地获取了元素分别为8个基本类型和Object的数组的首元素地址偏移量并缓存好 +public static final int ARRAY_BOOLEAN_BASE_OFFSET + = theUnsafe.arrayBaseOffset(boolean[].class); + +public static final int ARRAY_BYTE_BASE_OFFSET + = theUnsafe.arrayBaseOffset(byte[].class); + +public static final int ARRAY_SHORT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(short[].class); + +public static final int ARRAY_CHAR_BASE_OFFSET + = theUnsafe.arrayBaseOffset(char[].class); + +public static final int ARRAY_INT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(int[].class); + +public static final int ARRAY_LONG_BASE_OFFSET + = theUnsafe.arrayBaseOffset(long[].class); + +public static final int ARRAY_FLOAT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(float[].class); + +public static final int ARRAY_DOUBLE_BASE_OFFSET + = theUnsafe.arrayBaseOffset(double[].class); + +public static final int ARRAY_OBJECT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(Object[].class); + +// 获取数组中一个元素的字节大小 +public native int arrayIndexScale(Class arrayClass); + +// 贴心地获取了元素分别为8个基本类型和Object的数组的元素字节大小并缓存好 +public static final int ARRAY_BOOLEAN_INDEX_SCALE + = theUnsafe.arrayIndexScale(boolean[].class); + +public static final int ARRAY_BYTE_INDEX_SCALE + = theUnsafe.arrayIndexScale(byte[].class); + +public static final int ARRAY_SHORT_INDEX_SCALE + = theUnsafe.arrayIndexScale(short[].class); + +public static final int ARRAY_CHAR_INDEX_SCALE + = theUnsafe.arrayIndexScale(char[].class); + +public static final int ARRAY_INT_INDEX_SCALE + = theUnsafe.arrayIndexScale(int[].class); + +public static final int ARRAY_LONG_INDEX_SCALE + = theUnsafe.arrayIndexScale(long[].class); + +public static final int ARRAY_FLOAT_INDEX_SCALE + = theUnsafe.arrayIndexScale(float[].class); + +public static final int ARRAY_DOUBLE_INDEX_SCALE + = theUnsafe.arrayIndexScale(double[].class); + +public static final int ARRAY_OBJECT_INDEX_SCALE + = theUnsafe.arrayIndexScale(Object[].class); + +// 判断该类型是否需要初始化 +public native boolean shouldBeInitialized(Class c); + +// 确保类型已初始化 +public native void ensureClassInitialized(Class c); + +// 运行时创建类,可绕过JVM安全检查。其默认类加载器及保护域继承自调用者 +public native Class defineClass(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain); + +// 运行时创建匿名类,不关联任何类加载器或保护域,只要没有实例或者该类的Class对象的引用就可以被GC +public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); + + +// 创建实例,绕过构造函数调用等对象初始化阶段,即使没有公有构造函数依然可以用此方法创建实例 +public native Object allocateInstance(Class cls) + throws InstantiationException; +``` + + +#### 系统相关信息 +``` java +// 获取指针大小;32位系统返回4,64位系统返回8 +public native int addressSize(); + +// 贴心地获取了指针大小并缓存好 +public static final int ADDRESS_SIZE = theUnsafe.addressSize(); + +// 获取内存页大小 +public native int pageSize(); + +// 获取系统平均负载信息(uptime命令查看的系统过去1、5、15分钟三个样本的平均负载),可以选择获取几个样本 +public native int getLoadAverage(double[] loadavg, int nelems); +``` + + +#### 异常 +``` java +// 抛异常,可以像使用非受检异常一样抛受检异常 +public native void throwException(Throwable ee); +``` + + +#### 内存屏障 +内存屏障旨在解决2个问题: +1. 多核CPU缓存引发的数据可见性问题 +(1) 写数据时CPU可能只写入Store Buffer,还未同步到内存并通知其他CPU +(2) 内存更新的通知缓冲在Invalid Queue中还未来得及处理,CPU本地Cache中的数据其实已经失效 +这两点使得在一个CPU更新数据其他CPU并未及时感知到,即多线程共享变量可见性问题 + +2. CPU及编译器指令重排引发的有序性问题 +(1) 编译器和CPU都会进行指令的重排,一个线程下的指令乱序可能导致另一个线程结果不确定 +(2) Store Buffer也可能会引起写指令乱序,冲刷Store Buffer更新到内存的顺序不保证和写入Store Buffer的顺序相同,这会导致即使CPU写指令未乱序但其他CPU看到的数据更新可能是乱序的 + +CPU方面解决这两个问题的方法就是内存屏障,通常CPU提供了三种内存屏障指令: +1. LFENCE:即Load Barrier +(1) LFENCE 指令后的读指令不能重排到 LFENCE 指令之前,LFENCE 指令不能重排到 LFENCE 指令前的读指令之前。其实就是 LFENCE 指令两边的读指令不能跨越 LFENCE 指令这道屏障 +(2) LFENCE 指令清空Invalid Queue,使缓存在Invalid Queue中的失效信号得到响应,即失效对应的CPU缓存 +=> 这两点使 LFENCE 指令前的数据更新(更新到内存)对 LFENCE 指令后的读指令可见 + +2. SFENCE:即Store Barrier +(1) SFENCE 指令前的写指令不能重排到 SFENCE 指令之后,即SFENCE 指令前的写指令不能跨越 SFENCE 指令这道屏障 +(2) SFENCE 指令冲刷Store Buffer,将缓冲在Store Buffer中的更新数据更新到内存,并向其他CPU发出失效信号 +=> 这两点使 SFENCE 指令前的内存更新可以对其他CPU可见(当其他CPU响应了缓冲在Invalid Queue中的失效信号后才可见) + +3. MFENCE:即Full Barrier,集结了 LFENCE 和 SFENCE 的能力 + +对于X86架构CPU,采用强内存模型,对开发者并发编程提供了很大程度的支持,强保证了以下三种指令组合有序性: +1. 读指令不能和其他读指令重排序 +2. 写指令不能和之前的读指令重排序 +3. 写指令不能和其他写指令重排序 + +此外X86架构CPU采用FIFO的Store Buffer,保证冲刷顺序与写入顺序相同,其他CPU看到的更新不会乱序;另外X86架构CPU没有Invalid Queue缓冲,只要CPU冲刷了Store Buffer,其他CPU都可以立即响应响应缓存的失效 +因此在X86架构CPU下,CPU内存屏障指令在有序性问题上的效果实际为: +1. LFENCE:无效果,因为强内存模型已经保证了读指令不和其他读指令重排 +2. SFENCE:无效果,因为强内存模型已经保证了写指令不和其他写指令重排 +3. MFENCE:保证读指令不能和之前的写指令重排 + +在可见性问题上的效果实际为: +1. LFENCE:无效果,因为架构上没有Invalid Queue缓冲 +2. SFENCE:冲刷Store Buffer +3. MFENCE:冲刷Store Buffer + +因此在X86架构CPU下,LFENCE 和 SFENCE 几乎无开销或开销极小,而 MFENCE 相对来说开销昂贵,因为毕竟要阻挡读指令重排到写指令前 + + +在有序性方面,因为顺序总是对于两条读/写指令而言的,因此根据排列组合Java内存模型抽象出4种内存屏障语义: +1. LoadLoad +Load1; LoadLoad; Load2 +确保 Load1 先于 Load2 及其之后的所有读指令 +X86架构CPU强内存模型已保证,无需任何指令 +2. StoreStore +Store1; StoreStore; Store2 +确保 Store1 先于 Store2 及其之后所有写指令 +为了避免Store Buffer引发其他CPU看到数据更新乱序,通常在该屏障处让CPU冲刷Store Buffer让 Store1 的更新可以先对其他CPU可见 +X86架构CPU由于Store Buffer是FIFO,因此在该屏障处无需冲刷Store Buffer,再加上强内存模型保证写指令不重排,故无需任何指令 +3. LoadStore +Load1; LoadStore; Store2 +确保 Load1 先于 Store2 及其之后的所有写指令 +X86架构CPU强内存模型已保证,无需任何指令 + +4. StoreLoad +Store1; StoreLoad; Load2 +确保 Store1 (且对其他CPU可见)先于 Load2 及其之后所有读指令 +X86架构CPU需要使用 MFENCE 指令保证 + +因此在X86架构CPU下LoadLoad、StoreStore以及LoadStore语义的内存屏障实现上就是空操作;由于StoreLoad使用了大杀器 MFENCE,因此在效果上包含了所有其他三种语义的屏障(对于几乎所有架构的CPU,StoreLoad所采用的指令在效果上覆盖了其他三种语义的屏障) + +另外在Java内存模型中线程工作内存概念就是CPU缓存的抽象 + +同时编译器也遵守这些屏障的语义,在相应的屏障处按相应规则避免编译优化引起的乱序 + + +``` java +// 实现LoadLoad + LoadStore语义的屏障,即确保屏障前的读操作先于屏障后的读/写操作 +// 对于X86架构CPU就是空操作 +public native void loadFence(); + +// 实现StoreStore + LoadStore语义的屏障,即确保屏障前的读/写操作先于屏障后的写操作 +// 对于X86架构CPU就是空操作 +public native void storeFence(); + +// 实现StoreLoad语义的全能屏障,即确保屏障两边的读/写操作都不能跨越该屏障,且使屏障前的写操作结果对其他线程可见 +// 对于X86架构CPU就是相对昂贵的MFENCE指令(对任何架构的CPU实现都是相对其他屏障非常昂贵的) +public native void fullFence(); +``` + +volatile语义: +1. volatile读语义: +(1) 可见性:能读到该变量在其他线程更新的结果 +(2) 有序性:volatile读后的读/写操作不能重排到volatile读之前 +``` +[LFENCE] +volatile read +[LoadLoad] +[LoadStore] +``` +2. volatile写语义: +(1) 可见性:该变量的更新能够被其他线程看到 +(2) 有序性:volatile写前的读/写操作不能重排到volatile写之后 +``` +[StoreStore] +[LoadStore] +volatile write +[StoreLoad] // 不仅保证冲刷Store Buffer,同时保证和下面的volatile读操作不会乱序 +``` +`volatile` 关键字使变量在读取和赋值时分别具有volatile读和volatile写语义 + +volatile并不能解决读取-修改-更新操作的原子性问题 + +``` java +// 由变量o地址偏移offset按volatile读语义取对象 +public native Object getObjectVolatile(Object o, long offset); + +// 由变量o地址偏移offset按volatile写语义赋对象 +public native void putObjectVolatile(Object o, long offset, Object x); + +// 以下同上两个方法 +public native int getIntVolatile(Object o, long offset); + +public native void putIntVolatile(Object o, long offset, int x); + +public native boolean getBooleanVolatile(Object o, long offset); + +public native void putBooleanVolatile(Object o, long offset, boolean x); + +public native byte getByteVolatile(Object o, long offset); + +public native void putByteVolatile(Object o, long offset, byte x); + +public native short getShortVolatile(Object o, long offset); + +public native void putShortVolatile(Object o, long offset, short x); + +public native char getCharVolatile(Object o, long offset); + +public native void putCharVolatile(Object o, long offset, char x); + +public native long getLongVolatile(Object o, long offset); + +public native void putLongVolatile(Object o, long offset, long x); + +public native float getFloatVolatile(Object o, long offset); + +public native void putFloatVolatile(Object o, long offset, float x); + +public native double getDoubleVolatile(Object o, long offset); + +public native void putDoubleVolatile(Object o, long offset, double x); +``` + +lazy写(`putOrderedXXX`)类似volatile写,但只保证一部分有序性且不保证可见性,即lazy写前的读/写操作不能重排到lazy写之后,但不保证之后的操作不能重排到lazy前之前,此外不保证数据更新能够对其他线程可见 +``` +[StoreStore] +[LoadStore] +putOrderedXXX +// 这里相比volatile写没有StoreLoad屏障 +``` + +``` java +// 由变量o地址偏移offset按lazy写语义赋对象 +public native void putOrderedObject(Object o, long offset, Object x); + +// 以下同上个方法 +public native void putOrderedInt(Object o, long offset, int x); + +public native void putOrderedLong(Object o, long offset, long x); +``` + + +#### CAS操作 +CAS操作是通过CPU的原子性指令的支持,以非阻塞的方式保证了比较-更新操作的原子性,CAS操作主要用于构造无锁数据结构 + +在X86架构CPU下,CAS操作前后会有StoreLoad语义屏障 +``` java +// 由对象o地址偏移offset的变量值如果是expected,则用x替换并返回true(替换成功);否则(其他线程更新了变量值导致)不替换并返回false(替换失败) +public final native boolean compareAndSwapObject(Object o, long offset, + Object expected, + Object x); + +// 以下同上个方法 +public final native boolean compareAndSwapInt(Object o, long offset, + int expected, + int x); + +public final native boolean compareAndSwapLong(Object o, long offset, + long expected, + long x); + +// 将对象o地址偏移offset的int变量值原子性地增加delta,并返回被替换的int值 +public final int getAndAddInt(Object o, long offset, int delta) { + int v; + do { + // volatile读语义取当前int变量值 + v = getIntVolatile(o, offset); + // 尝试用CAS操作将该int变量替换为增加delta后的值,如果失败,则说明其他线程已修改该变量,当前获取的v已失效,因此循环再次重新获取变量值并尝试替换 + } while (!compareAndSwapInt(o, offset, v, v + delta)); + // 返回最后替换成功操作替换掉的变量值 + return v; +} + +// 以下同上个方法 +public final long getAndAddLong(Object o, long offset, long delta) { + long v; + do { + v = getLongVolatile(o, offset); + } while (!compareAndSwapLong(o, offset, v, v + delta)); + return v; +} + +// 将对象o地址偏移offset的int变量值原子性地替换为newValue,该方法可以返回被替换的int值 +public final int getAndSetInt(Object o, long offset, int newValue) { + int v; + do { + // volatile读语义取当前int变量值 + v = getIntVolatile(o, offset); + // 尝试用CAS操作将该int变量替换为newValue,如果失败,则说明其他线程已修改该变量,当前获取的v已失效,因此循环再次重新获取变量值并尝试替换 + } while (!compareAndSwapInt(o, offset, v, newValue)); + // 返回最后替换成功操作替换掉的变量值 + return v; +} + +// 以下同上个方法 +public final long getAndSetLong(Object o, long offset, long newValue) { + long v; + do { + v = getLongVolatile(o, offset); + } while (!compareAndSwapLong(o, offset, v, newValue)); + return v; +} + +public final Object getAndSetObject(Object o, long offset, Object newValue) { + Object v; + do { + v = getObjectVolatile(o, offset); + } while (!compareAndSwapObject(o, offset, v, newValue)); + return v; +} +``` + + +#### 线程调度 +``` java +// 唤醒因为调用park被阻塞的线程 +// 如果线程并未被阻塞,则下一次触发该线程park不会阻塞 +public native void unpark(Object thread); + +// 阻塞当前线程,直到其他线程触发该线程unpark,或者其他线程调用该线程的interrupt方法,或者超过了给定的超时时间 +// 如果time为0则表示不给定超时时间 +// 如果time大于0,如果isAbsolute为true则time为绝对时间,否则为相对时间 +public native void park(boolean isAbsolute, long time); +```