publicclassSemaphoreimplementsjava.io.Serializable{privatestaticfinallongserialVersionUID=-3222578661600680210L;/** All mechanics via AbstractQueuedSynchronizer subclass */privatefinalSyncsync;/** * Synchronization implementation for semaphore. Uses AQS state * to represent permits. Subclassed into fair and nonfair * versions. */abstractstaticclassSyncextendsAbstractQueuedSynchronizer{privatestaticfinallongserialVersionUID=1192457210091910933L;Sync(intpermits){setState(permits);}finalintgetPermits(){returngetState();}finalintnonfairTryAcquireShared(intacquires){for(;;){intavailable=getState();intremaining=available-acquires;if(remaining<0||compareAndSetState(available,remaining))returnremaining;}}protectedfinalbooleantryReleaseShared(intreleases){for(;;){intcurrent=getState();intnext=current+releases;if(next<current)// overflowthrownewError("Maximum permit count exceeded");if(compareAndSetState(current,next))returntrue;}}finalvoidreducePermits(intreductions){for(;;){intcurrent=getState();intnext=current-reductions;if(next>current)// underflowthrownewError("Permit count underflow");if(compareAndSetState(current,next))return;}}finalintdrainPermits(){for(;;){intcurrent=getState();if(current==0||compareAndSetState(current,0))returncurrent;}}}/** * NonFair version */staticfinalclassNonfairSyncextendsSync{privatestaticfinallongserialVersionUID=-2694183684443567898L;NonfairSync(intpermits){super(permits);}protectedinttryAcquireShared(intacquires){returnnonfairTryAcquireShared(acquires);}}/** * Fair version */staticfinalclassFairSyncextendsSync{privatestaticfinallongserialVersionUID=2014338818796000944L;FairSync(intpermits){super(permits);}protectedinttryAcquireShared(intacquires){for(;;){if(hasQueuedPredecessors())return-1;intavailable=getState();intremaining=available-acquires;if(remaining<0||compareAndSetState(available,remaining))returnremaining;}}}
publicfinalbooleanhasQueuedPredecessors(){// The correctness of this depends on head being initialized// before tail and on head.next being accurate if the current// thread is first in queue.Nodet=tail;// Read fields in reverse initialization orderNodeh=head;Nodes;returnh!=t&&((s=h.next)==null||s.thread!=Thread.currentThread());}