JUC锁框架源码阅读-Semaphore
介绍
使用demo可以参考《Semaphore信号量》
作用:限制并发资源的并发访问数量
获取许可
main
public static void main(String[] args) throws InterruptedException { //<c1>只允许10个并发同时处理 Semaphore samephore=new Semaphore(10); //<1>获取许可 samephore.acquire(); }
1.初始化调用父类的setState设置了父类支持的并发数量
2.调用AQS获取共享锁的方法
3.子类获取实现加锁逻辑是先判断CLH队列里面有没有等待线程,如果有则发挥获取失败交给父类处理。放入CLH队列
4.如果没有则自旋不断CAS(调用此方法compareAndSetState)尝试获取锁
5.如果state-1 小于0则直接返回失败 交给AQS放入CLH队列
<1>初始化
public Semaphore(int permits) { //<c2>初始化内部类NonfairSync传入数量 注:这里拿非公平的做例子。其实他也是支持公平的 详情看其他构造函数 sync = new Semaphore.NonfairSync(permits); }
<2>NonfairSync
//调用 Semaphore.Syn 继承父类的构造函数进行初始化 NonfairSync(int permits) { //<c3> super(permits); }
<3>Sync
//本质还是设置默认的state的值 Sync(int permits) { setState(permits); }
<1>acquire
public void acquire() throws InterruptedException { //<2>sync为内部类的对象 调用继承AQS的acquireSharedInterruptibly方法 sync.acquireSharedInterruptibly(1); }
<2>acquireSharedInterruptibly
可以参考《AQS源码阅读》
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { //判断是否线程中断 if (Thread.interrupted()) throw new InterruptedException(); //<4>调用子类的具体是实现的加锁方法 if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); }
<3>doAcquireSharedInterruptibly
/** * Acquires in shared interruptible mode. * @param arg the acquire argument */ private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { //创建共享节点 并插入队列 final AbstractQueuedSynchronizer.Node node = addWaiter(AbstractQueuedSynchronizer.Node.SHARED); boolean failed = true; try { //自旋 for (;;) { //获得节点的上一个节点 final AbstractQueuedSynchronizer.Node p = node.predecessor(); //如果他的节点就是节点头 尝试获取锁 因为并发情况节点头可能释放了 if (p == head) { //<4>子类实现具体加锁方法 int r = tryAcquireShared(arg); if (r >= 0) { //重新设节点头 并尝试唤醒其他等待节点 setHeadAndPropagate(node, r); p.next = null; // help GC failed = false; return; } } //如果前一个节点p的状态是Node.SIGNAL,就是调用parkAndCheckInterrupt方法阻塞当前线程 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) // 此时前一个节点pred的状态只能是0或者PROPAGATE,不可能是CONDITION状态 // CONDITION(这个是特殊状态,只在condition列表中节点中存在,CLH队列中不存在这个状态的节点) // 将前一个节点pred的状态设置成Node.SIGNAL,这样在下一次循环时,就是直接阻塞当前线程 cancelAcquire(node); } }
<4>tryAcquireShared
protected int tryAcquireShared(int acquires) { //自旋 for (;;) { //<29>判断队列是否需要排队 如果需要排队 直接返回false if (hasQueuedPredecessors()) return -1; int available = getState(); int remaining = available - acquires; //如果没有超过限制数量则自旋尝试获取 if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } }
释放许可
main
public static void main(String[] args) throws InterruptedException { //只允许10个并发同时处理 Semaphore samephore=new Semaphore(10); //<1>释放许可 samephore.release(); }
1.调用AQS释放共享锁方法
2.自身实现具体锁方法是获取state并+1
3.自旋加cas 设置新的state 设置成功返回释放成功,由AQS唤醒CLH等待队列线程
<1>release
public void release() { //<2>调用继承父类AQS的releaseShared sync.releaseShared(1); }
<2>releaseShared
可以参考《AQS源码阅读》
// 释放共享锁 public final boolean releaseShared(int arg) { // <3>模板模式 抽象方法尝试释放共享锁 if (tryReleaseShared(arg)) { //< 唤醒等待共享锁的线程 doReleaseShared(); return true; } return false; }
<3>tryReleaseShared
protected final boolean tryReleaseShared(int releases) { //自旋 for (;;) { //获取剩余释放数量 比如我前面设置的10 diao 10 调用release变成 int current = getState(); int next = current + releases; //判断是否超出可释放数量 if (next < current) // overflow throw new Error("Maximum permit count exceeded"); //CAS设置新的state if (compareAndSetState(current, next)) return true; } }