AQS 概述
全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架
特点:
- 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取 锁和释放锁
- getState - 获取 state 状态
- setState - 设置 state 状态
- compareAndSetState - cas 机制设置 state 状态
- 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
- 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList
- 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet
子类主要实现这样一些方法(默认抛出 UnsupportedOperationException)
- tryAcquire
- tryRelease
- tryAcquireShared
- tryReleaseShared
- isHeldExclusively
同步器实现
class MySync extends AbstractQueuedSynchronizer{
@Override //重写,原实现直接抛异常:尝试失败返回false,不进入阻塞
protected boolean tryAcquire(int acquire){
if(acquire==1){
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
}
return false;
}
@Override //重写,原实现直接抛异常:尝试失败返回false
protected boolean tryRelease(int arg) {
if (arg==1){
if (getState()==0){
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
return false;
}
@Override //重写,原实现直接抛异常
protected boolean isHeldExclusively() {
return getState()==1;
}
// 创建条件变量
protected Condition newCondition() {
return new ConditionObject();
}
}
锁实现
class MyLock implements Lock {
private MySync sync=new MySync();
@Override // 不成功,进入等待队列
public void lock() {
sync.acquire(1);
}
@Override // 不成功,进入等待队列,可打断
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override // 尝试一次,不成功返回false,不进入队列
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(1);
}
@Override // 生产条件变量
public Condition newCondition() {
return sync.newCondition();
}
}
测试
代码
public static void main(String[] args) {
MyLock lock=new MyLock();
new Thread(()->{
lock.lock();
System.out.println("加锁成功");
log.debug("加锁成功!");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
log.debug("释放锁");
lock.unlock();
}
}).start();
new Thread(()->{
lock.lock();
log.debug("加锁成功!");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
log.debug("释放锁");
lock.unlock();
}
}).start();
}
输出
加锁成功
19:02:47 [Thread-0] c.eight-AqsDiy - 加锁成功!
19:02:49 [Thread-0] c.eight-AqsDiy - 释放锁
19:02:49 [Thread-1] c.eight-AqsDiy - 加锁成功!
19:02:51 [Thread-1] c.eight-AqsDiy - 释放锁