1)概述
aqs全称AbstractQueuedSynchronizer【简称同步器】 ,是一个用来构建锁和同步工具的框架,ReentrantLock就是基于aqs构建的。这是一个抽象类,其子类中可以重写其中的各种同步操作方法来完成锁的实现。AQS同步器具有以下特点:
①aqs使用一个volatile修饰的原子变量state来表示锁的状态,具体代表什么状态可以由子类去定义,一般是用0代表未加锁,1代表已加锁,值得注意的是其中锁的状态的变化使用的是CAS操作;
②内部使用先进先出的队列来保存获取锁等待的线程对象,类似monitor中的EntryList;
③使用条件变量Condition 来实现等待唤醒,可以有多个条件变量,一种条件变量相当于monitor中的WaitSet;
为什么会有aqs的出现呢?在早期实现锁时一般都会使用一种同步器实现另一种同步器,因此后续jsr规范中提出aqs做统一的规范/提供统一的框架/模板,将实现锁的一些方法封装在里面,如果需要自定义锁则可以基于aqs做定制化,这也是一种模板方法模式。
自定义锁时需要重写的方法无非就是怎么获取锁怎么释放锁的操作,对应的就是对state的状态做什么样的改变。需要重写的钩子方法【一种被声明在抽象类中的方法,它可以是空方法(由子类实现),也可以是默认实现的方法】:
protected boolean tryAcquire(int arg); // 获取锁的操作【独占】
protected boolean tryRelease(int arg); // 释放锁的操作【独占】
protected int tryAcquireShared(int arg); // 获取锁的操作【共享】
protected boolean tryReleaseShared(int arg); // 释放锁的操作【共享】
protected boolean isHeldExclusively(); // 检查是否是独占锁
如果需要实现独占锁就重写独占型的方法,需要共享锁就重写共享型方法,当然也可以两种都实现【读写锁】。除了上述方法,aqs类中的其他方法都是final的,无法被重写。
2)自定义锁
如果我们要实现一个自定义锁,可以先实现Lock接口(MyLock),之后定义一个内部类继承AQS(MyAQS),这里的MyAQS为锁的实现者简化了锁的实现,MyLock为锁的使用者提供了与锁交互的接口。
/*
* 自定义AQS独占锁
*/
class MyLock implements Lock {
/*
* 静态内部类继承aqs
*/
private static class MySync extends AbstractQueuedSynchronizer {
/*
* 尝试获取锁的实现
*/
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
/*
* 尝试释放锁的实现
*/
@Override
protected boolean tryRelease(int arg) {
if (Thread.currentThread() == getExclusiveOwnerThread()) {
setExclusiveOwnerThread(null);
setState(0);
return true;
} else {
throw new IllegalMonitorStateException();
}
}
/*
* 是否是独占持有锁
*/
@Override
protected boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
/*
* 常见条件变量
*/
public Condition newCondition() {
return new ConditionObject();
}
}
private final MySync sync = new MySync();
/*
* 使用静态内部类的方法来实现Lock接口中的方法
*/
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(0);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
}
3)ReentrantLock的原理
独占锁获取锁的过程: