Java Concurrent Programming Series - (3) and the atomic CAS

3. atomic operation with CAS

3.1 atomic operation

Refers to the so-called atomic operations will not be interrupted thread scheduling mechanism operation; this operation once started, has been run to the end, without any intermediate context switch, i.e. switch to another thread.

In order to achieve an atomic operation, Java can be synchronized by a function key or the code block around to achieve atomicity operation. But the synchronized keyword has some very significant questions:

1, synchronized mechanism is based on blocking locks, if the blocked thread priority is high, it may be a long time do not have a chance to run other threads;
2, has not got the lock thread releases the lock, can lead to other threads have been waiting for;
3, the number of threads many may bring a lot of competition, consumption cpu, while bringing deadlock or other security.

This belongs to an exclusive lock as synchronized pessimistic lock, it is surely on the assumption that conflict, then the lock just useful addition, there are optimistic locking, optimistic locking meaning is the assumption that there is no conflict, then I can just carry out an operation, if the conflict if it, I'll retry until successful, optimistic locking is the most common CAS.

Internal JAVA class when implementing atomic operations are applied to the CAS.

3.2 CASE

CAS is CompareAndSwap acronym, that comparison and replacement. CAS requires three operands: a memory address V, the expected value of the old A, is about to be updated target B.

When the CAS instruction is executed, if and only if the memory address of the value of the expected value of V A is equal to the value of V memory address changed to B, otherwise it does nothing. Compare and replace the entire operation is an atomic operation, most modern processors support CAS commands.

About the JDK classes are atomic operation,

  • Update basic types of classes: AtomicBoolean, AtomicInteger, AtomicLong, AtomicReference

  • Update array class: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray

  • 更新引用类型:AtomicReference,AtomicMarkableReference,AtomicStampedReference

  • 原子更新字段类: AtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater

下面例子为AtomicInteger的基本用法,

public class UseAtomicInt {
    
    static AtomicInteger ai = new AtomicInteger(10);
    
    public static void main(String[] args) {
        System.out.println(ai.getAndIncrement());//10--->11
        System.out.println(ai.incrementAndGet());//11--->12--->out
        System.out.println(ai.get());
    }
}

深入getAndIncrement的实现可以发现,内部调用了CAS进行value的更新,

   /**
     * Atomically adds the given value to the current value of a field
     * or array element within the given object {@code o}
     * at the given {@code offset}.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param delta the value to add
     * @return the previous value
     * @since 1.8
     */
    @HotSpotIntrinsicCandidate
    public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!weakCompareAndSetInt(o, offset, v, v + delta));
        return v;
    }

CAS在底层通过JNI调用系统的Atomic::cmpxchg方法,来进行value的比较与更新。

对于CAS的实现,这依赖于CPU提供的特定指令,具体根据体系结构的不同还存在着明显区别。比如,x86 CPU 提供 cmpxchg 指令;而在精简指令集的体系架构中,则通常是靠一对儿指令(如“load and reserve”和“store conditional”)实现的,在大多数处理器上 CAS 都是个非常轻量级的操作,这也是其优势所在。

3.3 CAS的问题

CAS虽然很高效的解决了原子操作问题,但是CAS仍然存在三大问题。

  • ABA问题

什么是ABA问题?ABA问题怎么解决?如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说它的值没有被其他线程改变过了吗?如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。
Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。

  • 开销问题

循环时间长开销很大:我们可以看到getAndAddInt方法执行时,如果CAS失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。

  • 只能保证一个共享变量的原子操作

只能保证一个共享变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。


本文由『后端精进之路』原创,首发于博客 http://teckee.github.io/ , 转载请注明出处

搜索『后端精进之路』关注公众号,立刻获取最新文章和价值2000元的BATJ精品面试课程

后端精进之路.png

Guess you like

Origin www.cnblogs.com/way2backend/p/12019872.html