aqs
AQS(abstract queue synchronizer).为什么底层是cas+volatile
概念
aqs是一个框架,用来提供一种阻塞锁和一系列依赖等待队列的同步器框架比如reentrantlock,countdownlatch
使用方法是继承aqs并实现它的模版方法然后讲子类作为组件的内部类
是java自带的 synchronized以外的锁机制
接口
Lock接口,api
- lock
- trylock
- unlock
实现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里的函数
锁的释放
public final boolean release(int arg) {
//尝试释放锁
if (tryRelease(arg)) {
//如果有其他的头节点
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
//减去重入锁的次数
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果重入次数为0
if (c == 0) {
free = true;
//设置当前独占锁为null
setExclusiveOwnerThread(null);
}
//设置锁状态为0,无锁
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
//释放节点
LockSupport.unpark(s.thread);
}
解释aqs,要解释cas volatile