AQS浅学

AQS是什么:

1、 他是什么 :是ReentrantLock(独占)、Semaphore(共享)、CountDownLatch(共享)的核心基类。AQS有共享,独占两种模式。通过继承实现他的模版方法tryAcquire()、tryRelease()使用。

2、 用什么场景 :独占(串行执行的代码块,需要保证原子执行),就可以用到它再临界区加锁解锁

3、 独占实现

用state = 0 表示没线程竞争到锁资源。大于1表示锁被重入。

多个线程去CAS去竞争state变量,没有竞争到锁的线程会包装成Node去FIFO队列排队阻塞。

释放锁的线程去唤醒队头的线程争抢锁。

NonfairSync非公平的实现是不看队列有没有元素直接去CAS尝试争抢。

FairSync公平的实现是去队列排队。

AQS小细节:

为什么用CAS:防止多线程赋值state出错。

CAS是返回bool类型,JAVA虚拟机的CAS实现保证了原子性( 根据一个汇编的宏操作对多cpu前的cmpxchg指令加lock。因为cmpxchg本身不保证原子性( CAS本身要保证原子性,至少if判断和写回中间不能被打断)

注意:汇编本身指令也不保证原子性,一条指令可能会分成好步骤,中间被打断,一句.java编译成好几句.class就是JVM的汇编,JVM会把好几句汇编翻译成本地的汇编会变成更多句。

state状态,子类通过继承并通过实现它的方法管理其状态(acquire获取许可和release释放许可)。

Thread引用指向的当前已经获取到锁的线程;

Node节点成员

1、 共享还是独占模式下的Node等待标记。

//该节点是,在共享模式下等待的标记
static final Node SHARED = new Node();
//节点在是,在独占模式下等待的标记
static final Node EXCLUSIVE = null;

2、 节点状态

//独占锁需要的两个常量
//waitStatus值表示线程已经取消
static final int CANCELLED =  1;

//waitStatus值表示后继线程需要解除阻塞
static final int SIGNAL = -1;



//共享锁需要的两个常量
//waitStatus值表示线程正在等待
static final int CONDITION = -2;

//waitStatus值表示下一个被请求的应该无条件地传播
static final int PROPAGATE = -3;


//节点状态。
volatile int waitStatus;


//状态字段,只接受值1、-1、-2、-3、0五种值
//SIGNAL信号:此节点的后继马上被阻塞(通过park阻塞) 如果当前节点释放了同步状态或被取消,会通知后继节点去获取同步锁。

//CANCELLED取消:该节点因超时或中断被设置为取消值。这个节点不参与锁竞争且状态不会再改变。

//CONDITION条件:表示线程在等待触发条件(condition)当其他线程调用了Condition的signal()方法后,CONDITION状态的节点将从等待队列转移到同步队列中,等待获取同步锁,此节点当前处于条件队列中。它不会被用作同步队列节点直到转移,此时状态将设置为0。
(此处使用此值有和这个词的其他用法没有关系Field,但简化机制。)
 
//PROPAGATE传播:表示下一个acquireShared应无条件传播的waitStatus值。前驱节点不仅会唤醒其后继节点,同时也可能唤醒后继的后继节点。


//前驱
volatile Node prev;
//后继
volatile Node next;
//包装的线程
volatile Thread thread;
//下一个等待条件出发的节点
Node nextWaiter;

加锁过程:

尝试获取锁的线程失败会,包装成Node加入到等待队列尾部,插入到尾部的过程会一直CAS直到插入成功

拿到当前节点的pre节点,

如果pre是头节点,并且尝试获取锁成功了,把头节点删除,设置当前节点为头节点,

如果pre节点不是头节点,也没有尝试获取到锁,就判断当前线程是否需要阻塞,

解锁过程:

 获取当前节点状态(waitState值)如果小于0,把waitState设置为0,因为这个节点已经释放锁了不需要等待状态了,

读取当前节点的后继节点,如果后继节点waitState > 0 被取消或者后继节点为空,就从尾节点找到第一个有效节点唤醒。

为什么队列要用双向链表?

双链表有可以找前驱的指针。公平模式时:队列里抢占锁的节点会找到前驱是不是头节点。pre是头节点之后,再把头节点从队列里删除(头节点已经拿到了锁),把当前节点设置为头节点。

前驱不是头节点,说明我们可以阻塞,避免占用UPU资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值