CAS、AQS、锁以及并发工具

1. CAS原理

中文名叫比较交换---Compare And Swap

CAS(V,E,N)

V表示要更新的值;

E表示预期值;

N表示新值。

比较原则:当V和E相等时,才把N赋值给V;如果V和E不相等时,放弃当前修改;重新读取,再次尝试修改。

1.1 如何保证原子性

基于硬件的汇编指令实现原子性,使用CPU指令保证原子性;

 // Unsafe 后门类,用于直接操作内存中的数据
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}

private volatile int value;

/**
 * CAS实现
 */
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

/**
 * 使用自旋的方式保证线程安全
 */
public final int getAndUpdate(IntUnaryOperator updateFunction) {
    int prev, next;
    do {
        prev = get();
        next = updateFunction.applyAsInt(prev);
    } while (!compareAndSet(prev, next));
    return prev;
}

1.2 CAS的缺点

  • 循环时间太长

    有些类限制了自旋的次数

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

  • ABA问题

    如果一个值原来是A,变成了B,然后又变成了A,那么在CAS检查的时候会发现没有改变,但是实质上它已经发生了改变,这就是所谓的ABA问题。

    使用类AtomicStampedReference来解决ABA问题。

    如果当前引用 == 预期值,并且当前标志值 == 预期标志值,则就将当前引用和当前标志值赋值为更新值。

    /**
     * CAS实现
     *
     * @param expectedReference     引用的预期值
     * @param newReference          引用的新值
     * @param expectedStamp         标志的预期值
     * @param newStamp              标志的新值
     */
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }

2. AQS原理

AQS----AbstractQueuedSynchronizer的缩写

子类定义为非公共内部帮助器类(私有的内部类继承AQS);写锁的时候的一个帮助器,提供获取锁和是释放锁的功能模板。

acquire(int arg) 以独占模式获取对象,忽略中断。

acquireShared(int arg) 以共享模式获取对象,忽略中断。

tryAcquire(arg) 试图在独占模式下获取对象状态。

tryAcquireShared(int arg) 试图在共享模式下获取对象状态

release(int arg) 以独占模式释放对象。

releaseShared(int arg) 以共享模式释放对象

3. 并发工具类

3.1 CountDownLatch(查询航班)

3.2 CyclieBarries

3.3 Semaphore

猜你喜欢

转载自www.cnblogs.com/zhangqirong/p/11489398.html