1. AQS类理解

AQS如果作为一个幼儿园老师来看,她的小名叫"锁"老师,手里拿一个"state"的玩具按钮,负责有维护孩子们玩玩具"先来后到"的秩序。如果把其他小孩叫"线程"小朋友,当他们一起玩儿滑滑梯时,每次只能上一个。此时就需要"锁"老师来守在滑滑梯口儿上:小"线程"们奔过来,谁先把"锁"老师手里的按钮state按亮了,谁就先上;按不亮的,就让"锁"老师来给你前胸后背都给你贴一个挂钩,挂着前面比你先上的小朋友和你后面紧跟着的小朋友。
另外如果有某些"线程"小朋友要喝水,"锁"老师也给这些小朋友每个人头上戴一个帽子,帽子上写着下一个喝水的"线程"小朋友的名字。这样喝水也有顺序了。
上面的玩儿滑滑梯的顺序,前后的钩子,就是AQS里内部类Node里的prev/next引用,维护"阻塞队列"的FIFO顺序;它是双向的链表。
上面等喝水的小朋友帽子上的名字,就是Node里的nextWaiter引用,维护"条件队列"的顺序,它是单向的链表。

AQS类图:
image.png

2. AQS两个队列:阻塞队列和条件队列

2.1 阻塞队列

2.1.1 双向链表实现的FIFO队列

一个CLH队列,他是FIFO的,实现方式为双向链表的结构,具体结构定义见AQS的内部静态类Node,如果要公平实现,就是先来后到的。

image.png

2.1.2 双向链表结构Node

FIFO队列内节点的数据结构:内部类:Node

小程序加解密.png

2.2 条件队列

2.2.1 单向链表的条件队列:见Node的nextWaiter

阻塞队列是FIFO的,是双向链表,在Node链对象里是prev+next
条件队列是单向,只存储下一个等待者的引用,在Node里是nextWaiter;
使用方式如上所示

2.2.2 条件队列的条件结构:AQS>ConditionObject

条件队列的实现,也是在AQS中,体现在ReentrantLock里就是lock.newCondition()的Condition; sync本身就是AQS的子类. 看下面的源码:ReentrantLock的newCondition使用的是自己内部的Sync的newCondition(),而sync就是AQS,sync.newCondition()生成的就是ConditionObject。也就是AQS内部类的ConditionObject。

// ReentrantLock#newCondition
public Condition newCondition() {
   return sync.newCondition();
}
// ReentrantLock.Sync#newCondition
final ConditionObject newCondition() {
    return new ConditionObject();
}

2.3 一个实例

条件队列和可重入锁示例:

@Test
public void testConditional() throws InterruptedException {
    // AQS锁
    ReentrantLock lock = new ReentrantLock();
    // AQS条件
    Condition condition = lock.newCondition();

    Thread t1 = new Thread(() -> {
        System.out.println("======================t1.print==============");
        lock.lock();

        try {
            System.out.println("t1 await start ....");
            condition.await();
            System.out.println("t1 await end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    });

    Thread t3 = new Thread(() -> {
        System.out.println("======================t3.print==============");
        lock.lock();

        try {
            System.out.println("t3 await start ....");
            condition.await();
            System.out.println("t3 await end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    });

    Thread t2 = new Thread(() -> {
        System.out.println("======================t2.print==============");
        lock.lock();
        try {
            System.out.println("signal start ....");
            condition.signalAll();
            System.out.println("signal end");
        } finally {
            lock.unlock();
        }

    });

    t1.start();
    t3.start();
    Thread.sleep(400);
    t2.start();

}

输出结果如下:

======================t1.print==============
t1 await start ....
======================t3.print==============
t3 await start ....
======================t2.print==============
signal start ....
signal end
t1 await end
t3 await end

3.AQS的特征

3.1 抽象类

指明AQS是抽象类,所以它"有一些方法被作为模板模式被后代使用"

3.2 一个state状态

state 是int的,volatile的,是一个开关,关闭(state==0)表示AQS锁没被人占用;
state==1表示AQS锁被人占用了;
state大于1表示正以重入锁方式被当前独占线程占用。

3.3 父类还有个独占锁线程

Thread exclusiveOwnerThread持有独占锁的线程。

3.4 ReentrantLock类中的AQS子类

ReentrantLock中的Sync内部类继承了AQS,然后分别实现了两个锁:FairSync是公平锁;
NonFairSync是非公平锁;具体的实现,后面会详细记录一篇ReentrantLock。


丰木
322 声望19 粉丝

遇见超乎想象的自己!


引用和评论

0 条评论