今天和大家一起聊一聊AQS,

对于这个通用的同步器队列,

如果直接拿源码看的话,

是能看到方法的意思和对队列的各种操作,

但是感觉这样是一个没有灵魂的AQS,


上文说到Countdownlatch , ReentrantLock,Semphore都是基于AQS,就笔者感觉,日常Countdownlatch , ReentrantLock使用超过了Semaphore , 本着雨露均沾,我们今天通过Semaphore来看看AQS。


Semaphore:

对于Semaphore的理解和使用,我们参考Semaphore源代码的说明:

可以看到, 其核心的方法是 acquire(); 和 release();初始化时先初始化一个permits数量,调用accquire时会使permits减1 , 调用release时会使permits加1, 同样,accquire和release操作都是委托给AQS。

从上文借一张AQS的图,下面我们就跟着源码中的示例说明看下是怎么调用AQS的。

首选是Semaphore的构造函数。

我们传给Semaphore的permits被传给了AQS的构造器,根据fair去构造一个公平锁/非公平锁。示例代码构造了一个公平锁。跟踪源代码可以看到,最终是调用了Sync的setState方法,将传入的permits最终设置到了AQS的state值。

我们可以猜测,acquire和release应该都是对这个state进行判断和操作。

acquire()方法:

在调用acquire方法时,虽然我们没有传值,但实际上jdk默认帮我们传了1,也就是每次操作state只做加1或减1操作。继续跟踪acquire方法可以看到最终是调用了AQS的doAcquireSharedInterruptibly

1026: 向队列中添加一个节点,并获取到其引用node 。

1028: 不断尝试获取到node的前面一个节点p

1030: 如果p是头节点,开始尝试获取获取许可证,对Semaphore来说,就是操作AQS中的 state减1.

这里tryAcquireShared在Semaphore中被重写:

可以看到在251行,如果node前还有节点,则返回-1 。 就是要等节点p运行完,然后p.next=null. 释放p的引用,让p处于GCRoots不可达的状态,然后被GC回收。

如果获取失败,则入队,需不需要抛出中断, 需要则抛出一个中断异常,不需要,则进行下一次的尝试,直到获取成功 return;


总结:以上分析是基于公平锁进行的AQS分析,关于非公平锁的实现,有兴趣的小伙伴可以跟踪源码看下,期实比公平锁就多了一步, 来了不排队,先直接询问,我能不能获取到锁,能获取到,就直接获取,获取不到再老老实实排队去。