1. MyAQS介绍
在这个系列博客中,我们会参考着jdk的AbstractQueuedLongSynchronizer,从零开始自己动手实现一个AQS(MyAQS)。通过模仿,自己造轮子来学习主要有两个好处,一是可以从简单到复杂,从核心逻辑再到旁路逻辑的实现,学习曲线较为平滑;二是可以站在设计者的角度去思考实现具体功能时可以采用的各种方案的优劣,更深刻的理解其设计的精妙、关键之处。
AQS支持互斥和共享这两种工作模式,其中互斥模式比共享模式要简单许多。本着由浅入深的原则,本篇博客实现的MyAQS暂时只支持互斥模式。
MyAQS会按照顺序,逐步的实现互斥模式、共享模式、允许取消加锁(中断、超时退出)和支持条件变量这四个模块,具体内容会在后续的博客中分享出来。
1.1 乐观锁与CAS原理介绍
基于CAS策略的乐观锁机制是实现无锁并发的关键所在,因此在展开AQS的实现原理前需要先简单介绍一下乐观锁和CAS机制的原理。
悲观锁和乐观锁是用于控制线程并发安全的两种机制。为了防止不同线程并发读写临界区数据,悲观锁只允许一个线程进入临界区访问临界区数据。而没有竞争锁的其他线程将留在临界区之外(旋转或进入阻塞状态)。乐观锁基于比较和设置的思想,允许不同的线程同时访问和修改临界区数据,但确保同一时刻只有一个线程可以成功修改。从这个角度来看,乐观锁不是传统的锁概念,而更像是一种策略。
[En]
Pessimistic lock and optimistic lock are two mechanisms used to control thread concurrency security. In order to prevent the critical section data from being read and written concurrently by different threads, the pessimistic lock only allows one thread to enter the critical section to access the critical area data. while the other threads that do not compete for the lock will stay outside the critical zone (spin or enter blocking state). The optimistic lock is based on the idea of comparing and setting, which allows different threads to access and modify a critical area data concurrently, but ensures that only one thread can modify successfully at the same moment. From this point of view, optimistic locking is not a traditional concept of lock, but more like a strategy.
具体来说,乐观锁中每个线程在需要修改某一临界区数据前需要先读取当前数据的快照值(expect),然后执行一次cas操作(compareAndSet),如果CAS操作返回成功则说明修改成功,如果返回失败则说明对应数据在当前线程读取快照后、执行cas操作前的这段时间内有别的线程已经进行过修改,则需要重新读取出当前最新的快照值进行处理后再次尝试cas操作。
并发场景下cas操作可能会失败很多次,所以一般是放在一个循环中执行的,无限循环直到cas操作成功才结束。
CAS操作示例伪代码(CAS自增):