Java. util. concurrent package source code reading 17 semaphores Semaphore and semaphores semaphore
Anyone who has learned about the operating system knows the Semaphore. In the java. util. concurrent package, there is also a Semaphore implementation: Semaphore.
From the perspective of code implementation, semaphores and locks are similar. They can be regarded as a limited shared lock, that is, shared locks that can only be used by a limited number of threads.
Because there is a count, the Semaphore constructor has the permits parameter to set the count:
public Semaphore(int permits) { sync = new NonfairSync(permits); }
When thread queuing is involved, Semaphore also supports the fair and unfair modes:
public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); }
Speaking of thread queuing, we talked about AbstractQueuedSynchronizer when talking about "locks". It implements functions similar to acquiring locks and managing waiting threads. Therefore, this class is also required for the implementation of semaphores.
Abstract static class Sync extends actqueuedsynchronizer // implement static final class NonfairSync extends Sync // implement static final class FairSync extends Sync in Fair Mode
The Sync class uses the AbstractQueuedSynchronizer state to store the semaphore count:
Sync(int permits) { setState(permits); }
Because semaphores are similar to shared locks, the shared methods of AbstractQueuedSynchronizer are used to obtain and release resources.
Return to the previous unfair and fair modes again. This so-called fairness is reflected in the lock acquisition: unfair is the first thing to do, and fair is the first thing to do. Let's take a look at the two methods to get resources:
// Unfair mode final int nonfairTryAcquireShared (int acquires) {// check whether there are resources and check whether there are other queues (;;) {int available = getState (); int remaining = available-acquires; if (remaining <0 | compareAndSetState (available, remaining) return remaining ;}} // fair mode protected int tryAcquireShared (int acquires) {for (;) {// first check if there is any queued if (hasQueuedPredecessors () return-1; int available = getState (); int remaining = available-acquires; if (remaining <0 | compareAndSetState (available, remaining) return remaining ;}}
For semaphores, the process of obtaining resources is a process of updating the resource count. The same is true for releasing resources.
protected final boolean tryReleaseShared(int releases) { for (;;) { int current = getState(); int next = current + releases; if (next < current) // overflow throw new Error("Maximum permit count exceeded"); if (compareAndSetState(current, next)) return true; } }
The implementation of semaphores has the basis of AbstractQueuedSynchronizer and lock, which is quite understandable.