1. AQS类了解
AQS如果作为一个幼儿园老师来看,她的小名叫”锁”老师,手里拿一个”state”的玩具按钮,负责有保护孩子们玩玩具”先来后到”的秩序。如果把其余小孩叫”线程”小朋友,当他们一起玩儿滑滑梯时,每次只能上一个。此时就须要”锁”老师来守在滑滑梯口儿上:小”线程”们奔过去,谁先把”锁”老师手里的按钮state按亮了,谁就先上;按不亮的,就让”锁”老师来给你前胸后背都给你贴一个挂钩,挂着后面比你先上的小朋友和你前面紧跟着的小朋友。
另外如果有某些”线程”小朋友要喝水,”锁”老师也给这些小朋友每个人头上戴一个帽子,帽子上写着下一个喝水的”线程”小朋友的名字。这样喝水也有程序了。
下面的玩儿滑滑梯的程序,前后的钩子,就是AQS里外部类Node里的prev/next援用,保护”阻塞队列”的FIFO程序;它是双向的链表。
下面等喝水的小朋友帽子上的名字,就是Node里的nextWaiter援用,保护”条件队列”的程序,它是单向的链表。
AQS类图:
2. AQS两个队列:阻塞队列和条件队列
2.1 阻塞队列
2.1.1 双向链表实现的FIFO队列
一个CLH队列,他是FIFO的,实现形式为双向链表的构造,具体构造定义见AQS的外部动态类Node,如果要偏心实现,就是先来后到的。
2.1.2 双向链表构造Node
FIFO队列内节点的数据结构:外部类:Node
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。
发表回复