017 无锁与CAS

一 . 概述

我们知道加锁会对多线程的并发有影响,那么我们是否有无锁的方式保证线程的安全性呢?有的,就是CAS方式.

  CAS的核心就是乐观的尝试,将线程的阻塞变成了线程的尝试,认为即使在不断尝试的代价也比阻塞后唤醒的代价要小.


二 CAS

CAS到底是什么呢? 其实就是一个JVM的指令,其中这个指令的执行是原子性的,也就是说不会被打断.

  我们看下AtomicInter的原子实现:  

    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

我们看到使用了unsafe完成了CAS操作,CAS代表的就是比较并且更新(交换).

    当现在的值等于期待值就会更新并且返回ture,

    不等于就会返回false,并且不会更新.

    public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

我们看上述的JDK的实现,使用了一个while循环不断试探是否是线程安全的.

  我们知道while体内的操作可能不是安全的,也就是会发生修改修改,那么现在的值就和期待值不一致,那么CAS保证不去更新.

  循环就会再次尝试,知道成功为止.

  通过这种尝试的方式保证操作是线程安全的.


三 .ABA问题

我们知道,CAS不保证循环体的过程,但是保证结果是正确的,这也就是说循环体内

  可能发生了一个自减操作,然后又做出了一个自增操作,这种情况下,期待值和实际值确实是一致的,但是不能保证原子性了.

问题解决:

  解决的方式很简单,我们在原始的CAS之上加上一个时间戳,时间戳可以保证两次操作之间不应该有其它的操作.

  为此,出现了AtomicStampedReference这样的类可以保证线程安全.

猜你喜欢

转载自www.cnblogs.com/trekxu/p/8996782.html
017