**AQS:**全程是AbstractQueuedSynchronizer,是一个阻塞式锁和相关的同步器工具的框架。
其实AQS说白了就是一个可以给我们实现锁的框架,其内部是一个基于FIFO(先进先出)的队列,用state来代表锁的状态,0-没有获得锁,1-获得了锁,其内部定义了内部类ConditionObject
特点
用state属性来表示资源的状态,(state变量底层是被volatile修饰的),其拥有两种线程模式,独占模式
和共享模式
,子类需要定义如何维护这个状态,控制如何获取到锁以及如何释放锁,下面介绍下其常用api
getState: 用来获取state的状态,即查看该资源是否已经被锁住,0-无锁,1-已被锁住
setState : 用来设置state状态
compareAndSetState - 该方法是cas机制设置state的状态
独占模式是只有一个线程能够访问资源,而共享模式允许多个线程访问资源
AQS提供了基于先进先出的等待队列,有点类似于Monitor中的EntryList,通过条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet,在Lock包中的相关的锁(常用的有ReentrantLock、ReadWriteLock)都是基于AQS来构建的,一般也将AQS称作同步器
其自定义子类主要实现这样一些方法来实现锁的获取和释放(如下方法为独占模式)
- tryAcquire 尝试获得锁
- tryRelease 尝试释放锁
- isHeldExclusively 是否持有独占锁
/**
* 获取锁的姿势
* 如果获取失败了
*/
if(!tryAcquire(arg)){
// 入队列,可以选择阻塞当前线程,aqs中是通过park,unpark来阻塞线程的
}
// 释放锁的姿势
// 如果释放锁成功
if (tryRelease(arg)) {
// 让阻塞线程恢复运行
}
好了,AQS基本介绍就到这里,下面直接贴上通过AQS实现的自定义独占锁
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class TestAqs {
public static void main(String[] args) {
MyLock lock = new MyLock();
new Thread(()->{
lock.lock();
try {
System.out.println("加锁成功");
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("unlocking...");
lock.unlock();
}
},"t1").start();
new Thread(()->{
lock.lock();
try {
System.out.println("t2加锁成功");
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("unlocking...");
lock.unlock();
}
},"t2").start();
}
}
// 自定义锁 (不可重入锁)
class MyLock implements Lock{
// AQS -- 独占锁 同步器类
class MySync extends AbstractQueuedSynchronizer{
@Override // 尝试获取锁
protected boolean tryAcquire(int arg) {
if(compareAndSetState(0,1)){
// 如果CAS成功,则代表加上了锁,设置锁的owner为当前线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override // 尝试释放锁
protected boolean tryRelease(int arg) {
// 设置锁的持有线程为null,则代表当前没有线程获得锁
setExclusiveOwnerThread(null);
setState(0); //此处把state 放到后面写是为了防止指令重排序,因为exclusiveOwner没有volatile修饰
return true;
}
@Override //是否持有独占锁
protected boolean isHeldExclusively() {
return getState() == 1;
}
public Condition newCondition(){
return new ConditionObject();
}
}
private MySync sync = new MySync();
@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();
}
}