AQS是一个Java提供的底层同步工具类,用一个volatile int state的变量表示同步状态(代表共享资源),并提供了一系列的CAS操作来管理这个同步状态,同时还维护着一个FIFO线程同步队列(双向队列,多线程争用资源被阻塞时会进入此队列,使用unsafe进行线程的等待与唤醒)。
AQS的主要作用是为Java中的并发同步组件提供统一的底层支持,如常用的ReentrantLock,Semaphore,CountDownLatch等等就是基于AQS实现的,用法是通过继承AQS实现其模版方法,然后将子类作为同步组件的内部类。

image.png

image.png

state的访问方式有三种:

  • getState()
  • setState()
  • compareAndSetState()

AQS定义两种资源共享方式:

  • Exclusive(独占,只有一个线程能执行,如ReentrantLock)
  • Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)

自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,自定义同步器实现时主要实现以下几种方法:

  • isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
  • tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
  • tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
  • tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。

独占锁的示例

/**
 * 实现一个独占锁
 */
public class Mutex implements Lock {

    private static class Sync extends AbstractQueuedSynchronizer{
        //是否是独占
        protected boolean isHeldExclusively(){
            return getState() == 1;
        }

        //独占式只支持1个acquires
        public boolean tryAcquire(int acquires){
            if(compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //释放锁
        protected boolean tryRelease(int release){
            if(getState() == 0){
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        Condition newCondition(){
            return new ConditionObject();
        }

    }

    private final Sync sync = new Sync();

    @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();
    }

    //是否是独占锁
    public boolean isLock(){
        return sync.isHeldExclusively();
    }
    public boolean hasQueuedThreads(){
        return sync.hasQueuedThreads();
    }
}

示例中通过实现Lock接口,然后使用一个内部类继承AbstractQueuedSynchronizer来实现一个独占锁。

共享锁示例

/**
 * 共享锁示例
 */
public class SharedLockInstance implements Lock {

    private final Sync sync = new Sync(2);

    public LockInstance() throws IllegalAccessException {
    }

    //内部类继承AbstractQueuedSynchronizer
    private static final class Sync extends AbstractQueuedSynchronizer{
        Sync(int state) throws IllegalAccessException {
            if(state <= 0){
                throw new IllegalAccessException("count must large than 0");
            }
            setState(state);
        }

        @Override
        public int tryAcquireShared(int arg){
            for(;;){
                System.out.println("try acquire...");
                int current = getState();
                int now = current - arg;
                if(now < 0 || compareAndSetState(current,now)){
                    return now;
                }
            }
        }

        @Override
        public boolean tryReleaseShared(int arg){
            for(;;){
                System.out.println("try release...");
                int current = getState();
                int now = current + arg;
                if(compareAndSetState(current,now)){
                    return true;
                }
            }
        }

        Condition newCondition(){
            return new ConditionObject();
        }
    }

    @Override
    public void lock() {
        sync.acquireShared(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {

        return sync.tryAcquireShared(1) >= 0;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1,unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.tryReleaseShared(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}

不论是独占式锁还是共享锁都是在通过继承了AQS里的模板方法,这些模板方法大致分3类:独占式获取与释放同步状态,共享式获取与释放同步状态和查询同步队列中的等待线程情况。
一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。但AQS也支持自定义同步器同时实现独占和共享两种方式,如ReentrantReadWriteLock。

参考文章:Java并发之AQS详解
沉淀再出发:关于java中的AQS理解


步履不停
38 声望13 粉丝

好走的都是下坡路