首先juc并发包中,关于java并发组件,AQS是基本,是核心框架,很多的并发组件的功能都是由它代理完成。
每个Lock实现类中都有AQS的身影,每个Lock实现类的内部的同步器,都是继承自AQS,也就是说通过内部聚合同步器的子类,来代理完成,同步状态的管理,线程的排队,还有线程的等待和唤醒操作。通过下面的图可以发现。
AQS
首先带上AQS的UML图
image.png
ReentrantLock的非公平锁流程图解析:一图胜千言。
image.png只要根据这个图,然后对着源码走一遍,自然而然,就清楚,这个可重入锁的非公平锁是怎么实现,可重入又是怎么实现,然后一个节点同步状态的释放,怎么唤醒头结点的后继节点。然后获取锁的时候,又是如何自旋最后阻塞,后来或者被中断唤醒,或者是前驱节点唤醒。
然后是公平锁的实现
公平锁只是和非公平锁,有细微差别。获取锁时先判断该节点是否有前驱节点。内聚合的FairSync 调用的AQS中的模板方法acquire方法,获取同步状态
。我们知道这个模板方法,只管同步状态的获取或者释放,或者是共享的方式(内部Node节点有Shared模式决定)。至于获取同步状态前或者后面干什么,就是并发组件,自己去重写实现了,这听起来有点像aop中的@Before@After,像是代理模式,把一些同步状态,线程的排队,唤醒,挂起代理给AQS来。
非公平模式,内部的AQS子类,NonfairSync 的tryAquire()方法,一上来就是compareAndSetState(0,1).而公平模式 一上来先问有没有前驱。hasQueuedPredecessors中方法return ((s = h.next) == null || s.thread != Thread.currentThread()); 先判断head.next,s代表successor ,是不是为空,然后是不是当前线程。
公平性锁保证了锁的获取按照FIFO原则,而代价是进行大量的线程切换。非公平性锁虽 然可能造成线程“饥饿”,但极少的线程切换,保证了其更大的吞吐量。
网友评论