java学习|图说多线程(四)通过Semaphore看AQS

今天和大家一起聊一聊AQS

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

如果直接拿源码看的话,

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

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

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

java学习|图说多线程(四)通过Semaphore看AQS

Semaphore:

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

java学习|图说多线程(四)通过Semaphore看AQS

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

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

java学习|图说多线程(四)通过Semaphore看AQS

首选是Semaphore的构造函数。

java学习|图说多线程(四)通过Semaphore看AQS

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

java学习|图说多线程(四)通过Semaphore看AQS

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

acquire()方法:

java学习|图说多线程(四)通过Semaphore看AQS

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

java学习|图说多线程(四)通过Semaphore看AQS

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

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

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

这里tryAcquireSharedSemaphore中被重写:

java学习|图说多线程(四)通过Semaphore看AQS

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

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

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

java学习|图说多线程(四)通过Semaphore看AQS

java学习|图说多线程(四)通过Semaphore看AQS

END

前期回顾:

Java学习|图说String(一):String的存储方式

java学习|图说String(二):基于byte数组的String方法调用

java学习|图说String(三)String中'+'和StringBuilder的区别

QQ群:661749608

微信群请点击公众号菜单进微信群

我们哦~

java学习|图说多线程(四)通过Semaphore看AQS

文字: 微笑的小小刀

排版:花音