AQS(abstract queue synchronizer).为什么底层是cas+volatile
aqs是一个框架,用来提供一种阻塞锁和一系列依赖等待队列的同步器框架比如reentrantlock,countdownlatch
使用方法是继承aqs并实现它的模版方法然后讲子类作为组件的内部类
是java自带的 synchronized以外的锁机制
Lock接口,api
locktrylockunlock实现lock接口的有很多类,比如reentrantlock,readwritelock等
由于这些lock锁机制不是使用syn关键字实现的,那么如何使用竞争锁呢?
它本身没有实现任何同步的接口,只定义了同步状态的获取以及释放来提供自定义同步
aqs的功能分为独占以及共享.
aqs的同步功能依赖内部的队列Node类型(双向链表)
fairsync(公平锁.所有线程严格按照fifo获取锁),nofairsync(非公平锁,新线程也有机会抢锁),
队列:
aqs维护了一个队列,队列的第一位是当前占用线程,后面几位是等待线程,如果当前线程竞争锁失败则将当前线程保存到node中再阻塞该线程当获取锁的线程释放锁后,再从节点中唤醒一个阻塞的节点.
队列里出队入队都用cas操作,因为有一堆线程来加node尾巴
reentrantlock首先调用lock方法尝试获取锁,此处为多线程调用,内部实现为cas操作,其他线程都尝试获取锁,但是其中有一条线程一定是获取了锁的
final void lock() { if (compareAndSetState(0, 1))//cas操作 setExclusiveOwnerThread(Thread.currentThread());//设置当前获取锁的线程 else acquire(1);//继续尝试获取锁 } //尝试获取锁 public final void acquire(int arg) { //如果未获取到锁 if (!tryAcquire(arg) && //将当前线程封装进node中 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }使用cas操作对state赋值
/** * The synchronization state. */ private volatile int state;//设置成volatile线程间可见 当state=0时(默认)无锁当state>0时有线程获取了锁,重入锁允许设置多个锁,于是state会递增,释放锁时也需要释放多次让state变为0不同的aqs实现(锁),state表达的含义也是不一样的nofairtryAcquire
非公平锁尝试获取锁状态,获取当前线程,获取state的状态,修改state状态为1
addwaiter
当tryAcquire失败后,调用addwaiter方法(new Node)封装,当前Thread,与node属性,设置到等待队列中
enq
enq内部通过自旋的方式将node节点设置进队列中
acquireQueued
此方法内做抢占锁的操作.只有prev节点为head的节点才有机会抢占锁(tryAcquire,否则就挂起线程)
shouldparkAfterFailedAcquire
内部进行判断是否需要挂起线程,修改节点的链接状态(前置节点 后置节点)
parkAndCheckInterrupt
通过LockSupport.park方法将当前线程挂起到waiting状态,LockSupport使用了线程原语native方法,unsafe里的函数
解释aqs,要解释cas volatile