Semaphore(二)
了解Semaphore - 了解方法
源码浅析
方法
1 | // 主要方法 |
acquire()
acquire()是从Semaphore中获取一个许可证,如果没有可用的许可证的话,将会阻塞,直到有为止。或者在等待的过程中被中断了,也停止阻塞了。(也就是说是可以被中断的,继续看下去会看到不会被中断的acquire() )
1 | // Semaphore类中 |
acquireSharedInterruptibly():
1 | // AQS中 |
从AQS的方法中,我们看到了tryAcquireShared()这个方法。这个方法将会被其子类重写,也就是说执行到AQS这里的时候,就是体现java多态的时候。在Semaphore的FairSync,NonfairSync都继承了AQS,这里将会由一开始的 boolean fair参数去觉得Semaphore的Sync是哪个,如果是FairSync,就执行FairSync的tryAcquireShared方法。否则就执行NonfairSync的方法。
acquireUninterruptily()
从Semaphore中获取许可证,有可用许可证之前,将其堵塞。如果在等待过程中被中断,不会抛出异常,而是继续等待,不会发生中断,但是相比于没有发生中断而获取到许可证的时间,其在发生中断情况获取许可证的时间会有变化(应该是晚了)。当该方法获取了许可证,完成返回之后,将设置中毒呢状态。
1 | // Semaphore中 |
1 | // AQS中 |
tryAcquire()
1 | // Semaphore |
1 | final int nonfairTryAcquireShared(int acquires) { |
从源码可以看到,其会尝试获取1个可用的许可证。也就是如果Semaphore中有1个以上的许可证时,该方法将获取1个许可证并立即返回true,该许可证已经获取到手了。如果没有,那么该方法立即返回false。该方法不是探测有没有信号量,而是有的话给你拿到手,并且返回true,没有的话什么也不干,直接返回false。
在前面也提到了tryAcquire()无视什么fair不fair的。只要有就给你一个,才不会等你呢,直接插队,返回一个。在源码中也是直接体现在使用AQS的nonfairTryAcquireShared()方法。默认用不公平的策略
当然也可以使用tryAcquire去遵守公平策略,但这是另一个相似的方法tryAcquire(long timeout, TimeUnit unit):具体用法:tryAcquire(0, TimeUnit.SECONDS),该方法只要有许可证就返回,没有就返回false,继续等待。
tryAcquire(long timeout, TimeUnit unit)
如果在给定的时间timeout中,Semaphore有可用的许可证并且没有中断,那么将从Semaphore中获取一个许可证,并立即返回true。
如果在给定的时间中,没有可用的许可证,将会阻塞等待,直到
- Semaphore有可用的许可证,并且该线程将会是在队列中下一个获取许可证的线程,此时获取许可证,返回true。
- 超过了指定时间,此时将会返回false
- 被中断,抛出异常。
如果timeout小于或者等于0,则该方法不会等待,而是看看有没有可用的许可证,没有的就返回false,有就获取同时返回true。
1 | public boolean tryAcquire(long timeout, TimeUnit unit) |
1 | public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) |
相比于默认使用不公平策略,丝毫没有公平可言的tryAcquire()而言,tryAcquire(long timeout, TimeUnit unit)还是有公平可言的。其中调用了AQS的方法,而AQS方法里tryAcquireShared()可由FairSync和NonfairSync决定执行。
在之前tryAcquire()中,与tryAcquire()等效的公平设置tryAcquire(0, TimeUnit.SECONDS)中,timeout设置为0,意味着不会等待,而是一调用,如果有,就获取,返回true;如果没有,就返回false。跟tryAcquire()基本一致,是tryAquire()的公平版本。
release()
释放一个许可证,返回给信号量
1 | public void release() { |
1 | public final boolean releaseShared(int arg) { |
其他方法
上面是比较重要的几个方法,主要方法中还有几个,不过跟上面讲的基本一样,就是有的不再获取一个,可以获取用户指定数目的许可证数量。还有的可以直接减少许可证的数量。
而在其他方法中,可以简略地梳理一下:
- int availablePermits():返回此Semaphore中当前可用的许可证数量
- int drainPermits():获取并返回立即可用的所有许可证
- boolean isFair():判断是否是公平策略
- int getQueueLength():返回正在等待获取许可证的线程估计数目
- protected Collection < Thread >:返回可能等待获取的线程集合。
- boolean hasQueuedThreads():查询是否有线程正在等待获取。