基于AQS的锁

Posted nevergiveupzeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于AQS的锁相关的知识,希望对你有一定的参考价值。

  锁分为独占锁和共享锁,它们的主要实现都是依靠AbstractQueuedSynchronizer,这个类只提供一系列公共的方法,让子类来调用。基于我了解不深,从这个类的属性,方法,和独占锁的获取方式去了解这个类。

AbstractQueuedSynchronizer的主要属性和方法:

属性/方法 含    义
Thread exclusiveOwnerThread 这个是AQS父类AbstractOwnableSynchronizer的属性,表示独占模式同步器的当前拥有者
Node 上面已经介绍过了,FIFO队列的基本单位
Node head FIFO队列中的头Node
Node tail FIFO队列中的尾Node
int state 同步状态,0表示未锁
int getState() 获取同步状态
setState(int newState) 设置同步状态
boolean compareAndSetState(int expect, int update)  利用CAS进行State的设置 
 long spinForTimeoutThreshold = 1000L 线程自旋等待的时间 
Node enq(final Node node)  插入一个Node到FIFO队列中 
Node addWaiter(Node mode) 为当前线程和指定模式创建并扩充一个等待队列
void setHead(Node node) 设置队列的头Node
void unparkSuccessor(Node node) 如果存在的话,唤起Node持有的线程
void doReleaseShared() 共享模式下做释放锁的动作
void cancelAcquire(Node node) 取消正在进行的Node获取锁的尝试
boolean shouldParkAfterFailedAcquire(Node pred, Node node) 在尝试获取锁失败后是否应该禁用当前线程并等待
void selfInterrupt() 中断当前线程本身
boolean parkAndCheckInterrupt() 禁用当前线程进入等待状态并中断线程本身
boolean acquireQueued(final Node node, int arg) 队列中的线程获取锁
tryAcquire(int arg) 尝试获得锁(由AQS的子类实现它
tryRelease(int arg) 尝试释放锁(由AQS的子类实现它
isHeldExclusively() 是否独自持有锁
acquire(int arg) 获取锁
release(int arg) 释放锁
compareAndSetHead(Node update) 利用CAS设置头Node
compareAndSetTail(Node expect, Node update) 利用CAS设置尾Node
compareAndSetWaitStatus(Node node, int expect, int update) 利用CAS设置某个Node中的等待状态

可以看出这个类是一个链表结构,拥有head和tail,next,它的同步状态是通过int类型 state来表示的,0表示未获取,1表示获取,大于1表示重入数,compareAndSetState(int expect,int update)和spinForTimeoutThreshold是在多线程下插入节点到队列时保证快速和唯一正确的。compareAndSetState 和 setState 都是设置state的值,可以看源代码,发现compareAndSetState主要是获得锁,多线程竞争的时候使用,而setState则在锁重入的时候使用,有偏向锁的作用。

AQS是一个基于FIFO的队列的实现,有一个Node的内部类,主要属性如下如下:

属    性 定    义
Node SHARED = new Node() 表示Node处于共享模式
Node EXCLUSIVE = null 表示Node处于独占模式
int CANCELLED = 1 因为超时或者中断,Node被设置为取消状态,被取消的Node不应该去竞争锁,只能保持取消状态不变,不能转换为其他状态,处于这种状态的Node会被踢出队列,被GC回收
int SIGNAL = -1 表示这个Node的继任Node被阻塞了,到时需要通知它
 int CONDITION = -2 表示这个Node在条件队列中,因为等待某个条件而被阻塞 
int PROPAGATE = -3 使用在共享模式头Node有可能处于这种状态, 表示锁的下一次获取可以无条件传播
 int waitStatus 0,新Node会处于这种状态 
 Node prev 队列中某个Node的前驱Node 
 Node next 队列中某个Node的后继Node 
Thread thread 这个Node持有的线程,表示等待锁的线程
Node nextWaiter 表示下一个等待condition的Node

获取独占锁的状态示意图如下:

 

以上是关于基于AQS的锁的主要内容,如果未能解决你的问题,请参考以下文章

一文彻底搞懂ReentrantLock原理基于AQS的公平锁+非公平锁

一文彻底搞懂ReentrantLock原理基于AQS的公平锁+非公平锁

AQS(面试)

同步队列器AQS的实现原理

老板让只懂Java基本语法的我,基于AQS实现一个锁

AQS解析与实战