zoukankan      html  css  js  c++  java
  • 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}.
         *
         * <p>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.
     *
     * <em>Note:</em> 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.
         *
         * <p>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.
         *
         * <p>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.
         *
         * <p>Here is a suggested idiom for using unsafe operations:
         *
         * <pre> {@code
         * class MyTrustedClass {
         *   private static final Unsafe unsafe = Unsafe.getUnsafe();
         *   ...
         *   private long myCountAddress = ...;
         *   public int getCount() { return unsafe.getByte(myCountAddress); }
         * }}</pre>
         *
         * (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;
        }

    关于 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.
     *
     * <em>Note:</em> 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.
         *
         * <p>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.
         *
         * <p>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.
         *
         * <p>Here is a suggested idiom for using unsafe operations:
         *
         * <pre> {@code
         * class MyTrustedClass {
         *   private static final Unsafe unsafe = Unsafe.getUnsafe();
         *   ...
         *   private long myCountAddress = ...;
         *   public int getCount() { return unsafe.getByte(myCountAddress); }
         * }}</pre>
         *
         * (It may assist compilers to make the local variable {@code final}.)
         */
        public static Unsafe getUnsafe() {
            return theUnsafe;
        }

    该类中有很多CompareAndSetXXX方法

     

    剖析compareAndSetInt

        /**
         * Atomically updates Java variable to {@code x} if it is currently
         * holding {@code expected}.
         *
         * <p>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/

  • 相关阅读:
    bestcoder 48# wyh2000 and a string problem (水题)
    Install OpenCV3.0 on Eclipse
    sql 优化 -- sql中的自定函数
    java基础知识总结1
    【Java】日志知识总结和经常使用组合配置(commons-logging,log4j,slf4j,logback)
    ESLint 配置
    Vue命名规范
    在vue中使用jsx语法
    vue中8种组件通信方式, 值得收藏!
    Vue+Express实现登录状态权限控制
  • 原文地址:https://www.cnblogs.com/studyLog-share/p/15120573.html
Copyright © 2011-2022 走看看