AQS中的条件队列操作

/ 默认分类 / 0 条评论 / 1642浏览

AQS中的条件队列操作

一.前言

我们知道,在同步锁synchronized中,我们可以使用wait(),notify(),notifyAll()这些操作来实现线程状态控制,那在AQS中其实也可以实现 这样的操作.

二.分析

AQS中实现了一个条件队列的类

class ConditionObject implements Condition{
            private transient Node firstWaiter;
            /** Last node of condition queue. */
            private transient Node lastWaiter;
}

该队列存放的也是Node节点,注意区分,这不是我们之前介绍的AQS同步阻塞双向队列,该条件队列实现了Condition接口,接口如下: Condition接口

这里先来介绍下大致的逻辑,一个AQS同步器中可以包含很多个条件队列变量,当线程1获取到锁后,如果调用某一个条件队列变量的 await方法,那么线程1就会释放当前获取的锁,并被park阻塞挂起,并封装为Node节点存储到该条件队列中,如果有其他线程也这样操作,就会加到该条件队列 尾部,之后如果其他线程调用该条件队列变量的singal方法,那么就会将该条件队列首部的Node放入AQS同步阻塞队列,表示唤醒了这个线程让他进入 同步阻塞队列尝试获取锁.所以同步器(同步阻塞队列)和条件队列的关系可以用下面这张图来描述:

下面是条件队列中的几个重要的操作:

这些api的作用都显而易见,对比这同步锁synchronized中的操作来理解

三.基于AQS自定义一个不可重入的独占锁

public class NoneReentrantLock implements Lock {

    public static class Sync 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(getState() == 0){
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

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

    }

    Sync sync;

    public NoneReentrantLock() {
        this.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.tryRelease(1);
    }

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

这里补充下,关于lock()和tryLock(),之前在介绍AQS时漏掉了,其实很容易理解,lock()调用就是获取锁,并且如果获取失败会加入到AQS同步阻塞队列中继续不断尝试获取 但是tryLock()调用只是尝试一次获取锁,如果获取到就返回true,没有就立刻返回false,不会进行acquireQueued()等操作;