概述
AQS全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架
特点:
- 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取
锁和释放锁
getState - 获取 state 状态
setState - 设置 state 状态
compareAndSetState - cas 机制设置 state 状态
独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源 - 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList
- 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet
子类主要实现这样一些方法(默认抛出 UnsupportedOperationException)
tryAcquire
tryRelease
tryAcquireShared
tryReleaseShared
isHeldExclusively
获取锁的姿势:
// 如果获取锁失败
if (!tryAcquire(arg)) {
// 入队, 可以选择阻塞当前线程 park unpark
}
释放锁的姿势:
// 如果释放锁成功
if (tryRelease(arg)) {
// 让阻塞线程恢复运行
}
实现不可重入锁
自定义队列同步器
//自定义队列同步器的实现
final class MyAQS extends AbstractQueuedSynchronizer{
//尝试获取锁只有一次
@Override
protected boolean tryAcquire(int arg) {
if (arg == 1){
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
setState(1);
return true;
}
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
//这里别写错了是1不是0 我写错了锁没释放...
if (arg == 1){
setExclusiveOwnerThread(null);
setState(0);
return true;
}
return false;
}
//当前线程是否持有锁
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
protected Condition newCondition(){
return new ConditionObject();
}
}
自定义锁(不可重入锁)
public class MyLock implements Lock {
MyAQS sync = new MyAQS();
//如果获取锁失败,会将其加入到同步队列中
//而tryAcquire是获取一次失败拉倒 acquired内部是tryAcquire 需要我们自己实现它
@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(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
}
日志依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>2.0.13</version>
</dependency>
</dependencies>