java并发:CAS、Unsafe
CAS
CAS即CompareandSwap,其具体的意思是比较并交换。
它是JDK提供的非阻塞原子性操作,它通过硬件保证了“比较、更新”操作的原子性。
Unsafe
JDK 里的 Unsafe 类提供了一系列的 compareAndSwap*方法,代码文件路径如下:
其定义了如下几个 compareAndSwap*方法:
剖析compareAndSwapInt
相关代码定义如下:
/** * Atomically updates Java variable to {@code x} if it is currently * holding {@code expected}. * *This operation has memory semantics of a {
@code volatile} read * and write. Corresponds to C11 atomic_compare_exchange_strong. * * @return {@code true} if successful */ @ForceInline public final boolean compareAndSwapInt(Object o, long offset, int expected, int x) { return theInternalUnsafe.compareAndSetInt(o, offset, expected, x); }
从上述代码可以看到CAS有四个操作数,分别是:对象内存位置、对象中的变量的偏移量、变量预期值和新值。
具体含义:
如果对象 obj 中内存偏移量为 valueOffset的变量的值为 expect,则使用新值 update替换旧值 expect;这是处理器提供的一个原子性指令。
Note:
从上述方法的定义可以发现其实际上是调用了变量 theInternalUnsafe 的 compareAndSetInt 方法,该变量在类中的定义如下:
/** * A collection of methods for performing low-level, unsafe operations. * Although the class and all methods are public, use of this class is * limited because only trusted code can obtain instances of it. * * Note: It is the resposibility of the caller to make sure * arguments are checked before methods of this class are * called. While some rudimentary checks are performed on the input, * the checks are best effort and when performance is an overriding * priority, as when methods of this class are optimized by the * runtime compiler, some or all checks (if any) may be elided. Hence, * the caller must not rely on the checks and corresponding * exceptions! * * @author John R. Rose * @see #getUnsafe */ public final class Unsafe { static { Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); } private Unsafe() {} private static final Unsafe theUnsafe = new Unsafe(); private static final jdk.internal.misc.Unsafe theInternalUnsafe = jdk.internal.misc.Unsafe.getUnsafe(); /** * Provides the caller with the capability of performing unsafe * operations. * ** * (It may assist compilers to make the local variable {@code final}.) * * @throws SecurityException if the class loader of the caller * class is not in the system domain in which all permissions * are granted. */ @CallerSensitive public static Unsafe getUnsafe() { Class<?> caller = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; }The returned {
@code Unsafe} object should be carefully guarded * by the caller, since it can be used to read and write data at arbitrary * memory addresses. It must never be passed to untrusted code. * *Most methods in this class are very low-level, and correspond to a * small number of hardware instructions (on typical machines). Compilers * are encouraged to optimize these methods accordingly. * *
Here is a suggested idiom for using unsafe operations: * *
{@code * class MyTrustedClass { * private static final Unsafe unsafe = Unsafe.getUnsafe(); * ... * private long myCountAddress = ...; * public int getCount() { return unsafe.getByte(myCountAddress); } * }}
关于 theInternalUnsafe 将在后面详细讲述。
ABA 问题
关于CAS操作有个经典的ABA问题,具体案例如下:
线程I在获取变量X的值(变量X的初始值是A)后使用CAS操作将其修改为 B,假设操作成功,则程序运行一定是正确的吗?
其实未必,在线程I获取变量 X 的值后,在执行 CAS 前,线程II使用 CAS 修改变量X的值为B,随后又使用CAS修改变量X的值为A;则该场景中线程I在执行CAS时X的值虽然是A,但这个A己经不是线程I获取的A了。
ABA 问题的产生是因为变量的状态值产生了环形转换,即变量的值从 A 到 B, 然后再从 B 到 A。
如果变量的值只能朝着一个方向转换,比如 A 到 B,B 到 C,不构成环形,则不会存在问题。
JDK 中的 AtomicStampedReference 类给每个变量的状态值都配备了一个时间戳,从而避免了ABA问题的产生。
theInternalUnsafe
前述 compareAndSwapInt 方法中使用的 theInternalUnsafe 也是Unsafe类的实例,由此可知JDK里还存在另一个 Unsafe 类,代码文件路径如下:
这两个Unsafe类对应的包名如下图所示
由JDK11中AtomicInteger的定义,知其使用的是jdk.internal.misc.Unsafe。
(JDK8中使用的是sun.misc.Unsafe,地址)
AtomicInteger的代码片段如下:
/** * An {@code int} value that may be updated atomically. See the * {@link VarHandle} specification for descriptions of the properties * of atomic accesses. An {@code AtomicInteger} is used in * applications such as atomically incremented counters, and cannot be * used as a replacement for an {@link java.lang.Integer}. However, * this class does extend {@code Number} to allow uniform access by * tools and utilities that deal with numerically-based classes. * * @since 1.5 * @author Doug Lea */ public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; /* * This class intended to be implemented using VarHandles, but there * are unresolved cyclic startup dependencies. */ private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe(); private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value"); private volatile int value; /** * Creates a new AtomicInteger with the given initial value. * * @param initialValue the initial value */ public AtomicInteger(int initialValue) { value = initialValue; } /** * Creates a new AtomicInteger with initial value {@code 0}. */ public AtomicInteger() { }
jdk.internal.misc.Unsafe对应的代码片段如下:
/** * A collection of methods for performing low-level, unsafe operations. * Although the class and all methods are public, use of this class is * limited because only trusted code can obtain instances of it. * * Note: It is the resposibility of the caller to make sure * arguments are checked before methods of this class are * called. While some rudimentary checks are performed on the input, * the checks are best effort and when performance is an overriding * priority, as when methods of this class are optimized by the * runtime compiler, some or all checks (if any) may be elided. Hence, * the caller must not rely on the checks and corresponding * exceptions! * * @author John R. Rose * @see #getUnsafe */ public final class Unsafe { private static native void registerNatives(); static { registerNatives(); } private Unsafe() {} private static final Unsafe theUnsafe = new Unsafe(); /** * Provides the caller with the capability of performing unsafe * operations. * ** * (It may assist compilers to make the local variable {@code final}.) */ public static Unsafe getUnsafe() { return theUnsafe; }The returned {
@code Unsafe} object should be carefully guarded * by the caller, since it can be used to read and write data at arbitrary * memory addresses. It must never be passed to untrusted code. * *Most methods in this class are very low-level, and correspond to a * small number of hardware instructions (on typical machines). Compilers * are encouraged to optimize these methods accordingly. * *
Here is a suggested idiom for using unsafe operations: * *
{@code * class MyTrustedClass { * private static final Unsafe unsafe = Unsafe.getUnsafe(); * ... * private long myCountAddress = ...; * public int getCount() { return unsafe.getByte(myCountAddress); } * }}
该类中有很多CompareAndSetXXX方法
剖析compareAndSetInt
/** * Atomically updates Java variable to {@code x} if it is currently * holding {@code expected}. * *This operation has memory semantics of a {
@code volatile} read * and write. Corresponds to C11 atomic_compare_exchange_strong. * * @return {@code true} if successful */ @HotSpotIntrinsicCandidate public final native boolean compareAndSetInt(Object o, long offset, int expected, int x); @HotSpotIntrinsicCandidate public final native int compareAndExchangeInt(Object o, long offset, int expected, int x); @HotSpotIntrinsicCandidate public final int compareAndExchangeIntAcquire(Object o, long offset, int expected, int x) { return compareAndExchangeInt(o, offset, expected, x); } @HotSpotIntrinsicCandidate public final int compareAndExchangeIntRelease(Object o, long offset, int expected, int x) { return compareAndExchangeInt(o, offset, expected, x); } @HotSpotIntrinsicCandidate public final boolean weakCompareAndSetIntPlain(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); } @HotSpotIntrinsicCandidate public final boolean weakCompareAndSetIntAcquire(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); } @HotSpotIntrinsicCandidate public final boolean weakCompareAndSetIntRelease(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); } @HotSpotIntrinsicCandidate public final boolean weakCompareAndSetInt(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); }
从上述代码可以看到该Unsafe类中的compareAndSetInt 和 compareAndExchangeInt方法都是 native方法,它们使用 JNI 的方式访问本地C++实现库。
参考资料:
https://howtodoinjava.com/java/multi-threading/compare-and-swap-cas-algorithm/