Java学习总结:Atomic、CAS、AQS、ReentrantLock和CountDownLock

JUC包

AtomicInteger底层实现原理是什么?-->一个Unsafe操作获取内存地址,一个Volatile保证value的可见性,CAS进行重试。

原子更新方法:getAndIncrement-->Unsafe会利用value字段的内存地址偏移,直接完成操作 ?

Atomic 包提供了最常用的原子性数据类型,甚至是引用、数组等相关原子类型和更新操作工具,是很多线程安全程序的首选。

CAS-->获取当前数值,进行一些运算,利用CAS指令试图进行更新。如果当前数值未变,代表没有其他线程进行并发修改,则成功更新。否则,可能出现不同的选择,要么进行重试,要么就返回一个成功或者失败的结果。

            CAS有三个操作数:内存地址,旧的预期值,新值

CAS更加底层:依赖于CPU提供的特定指令

在什么场景下,可以采用 CAS 技术,调用 Unsafe 毕竟不是大多数场景的最好选择,有没有更加推荐的方式呢?

CAS缺点:试错机制占用CPU,适合小任务;ABA,stamp版本

AbstractQueuedSynchronizer(AQS)-->是 Java 并发包中,实现各种同步结构和部分其他组成单元(如线程池中的 Worker)的基础。

AQS就是将基础的同步相关操作抽象在 AbstractQueuedSynchronizer 中,利用 AQS 为我们构建同步结构提供了范本。

AQS = 一个volatile的整数成员表征状态(同时提供了setState()和getState()方法)+ 一个先入先出(FIFO)的等待线程队列,以实现多线程间竞争和等待 + 各种基于CAS的基础操作方法,以及各种期望具体同步结构去实现的acquire/release方法

利用AQS实现一个同步结构-->需要实现acquire操作,获取资源的独占权;release操作,释放对某个资源的独占

对 ReentrantLock、CyclicBarrier 等并发结构底层的实现技术的理解。

可重入锁ReentrantLock,内部通过扩展AQS实现了Sync类型,以AQS的state来反应锁的持有情况

acquire方法逻辑,其直接实现是在AQS内部,调用了tryAcquire和acquireQueued

在可重入锁种,tryAcquire逻辑实现在NonfairSync和FairSync中,分别提供了进一步的非公平或公平性方法,而AQS内部tryAcquire仅仅是个接近未实现的方法(直接抛异常),这是留给实现者自己定义的操作

以非公平的tryAcquire为例,其内部实现了如何配合状态与CAS获取锁,对比公平版本的tryAcquire,它在锁无人占有时,并不检查是否有其他等待者,这里体现了非公平的语义。

nonfairTryAcquire实现-->获取当前AQS内部状态量;返回0表示无人占有,则直接用CAS修改状态位;如果不是0,但等于当前线程id,继续后续操作,setState;如果都不是报错。

acquireQueued-->如果tryAcquire失败,线程间对锁的竞争通过FIFO队列实现。当前线程会被包装成为一个排他模式的节点,通过addWaiter方法添加到队列中。acquireQueued的逻辑,就是如果当前节点的前面是头节点,则试图获取锁,一切顺利则成为新的头节点;否则,有必要则等待

tryAcquire 是按照特定场景需要开发者去实现的部分,而线程间竞争则是 AQS 通过 Waiter 队列与 acquireQueued 提供的,在 release 方法中,同样会对队列进行对应操作。

猜你喜欢

转载自www.cnblogs.com/liushoudong/p/12747971.html