/** * Synchronization implementation for semaphore. Uses AQS state * to represent permits. Subclassed into fair and nonfair * versions. */ abstractstaticclassSyncextendsAbstractQueuedSynchronizer { privatestaticfinallongserialVersionUID=1192457210091910933L;
/** * Fair version */ staticfinalclassFairSyncextendsSync { privatestaticfinallongserialVersionUID=2014338818796000944L;
FairSync(intpermits) { super(permits); }
//共享模式下,公平的tryAcquireShared方法,公平是指,当执行tryAcquireShared protectedinttryAcquireShared(int acquires) { for (;;) { //sync queue不为空,且当前线程不是第二个节点时hasQueuedPredecessors()返回true if (hasQueuedPredecessors()) //返回-1,那么当前线程将会被AQS添加到sync queue中去 return -1; intavailable= getState(); //剩余许可的数量 intremaining= available - acquires; //当许可不足时,或者CAS操作成功时返回剩余许可数量 if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } }
3 字段
Semaphore仅有一个字段,即上面的内部类Sync的实例。信号量的语义是靠sync来实现的
1 2
/** All mechanics via AbstractQueuedSynchronizer subclass */ privatefinal Sync sync;
4 重要方法
4.1 构造方法
该构造方法创建指定数量的许可
1 2 3 4 5 6 7 8 9 10 11
/** * Creates a {@code Semaphore} with the given number of * permits and nonfair fairness setting. * * @param permits the initial number of permits available. * This value may be negative, in which case releases * must occur before any acquires will be granted. */ publicSemaphore(intpermits) { sync = newNonfairSync(permits); }
该构造方法创建指定数量的许可,并且指定公平模式还是非公平模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/** * Creates a {@code Semaphore} with the given number of * permits and the given fairness setting. * * @param permits the initial number of permits available. * This value may be negative, in which case releases * must occur before any acquires will be granted. * @param fair {@code true} if this semaphore will guarantee * first-in first-out granting of permits under contention, * else {@code false} */ publicSemaphore(intpermits, boolean fair) { sync = fair ? newFairSync(permits) : newNonfairSync(permits); }
/** * Acquires a permit from this semaphore, blocking until one is * available, or the thread is {@linkplain Thread#interrupt interrupted}. * * <p>Acquires a permit, if one is available and returns immediately, * reducing the number of available permits by one. * * <p>If no permit is available then the current thread becomes * disabled for thread scheduling purposes and lies dormant until * one of two things happens: * <ul> * <li>Some other thread invokes the {@link #release} method for this * semaphore and the current thread is next to be assigned a permit; or * <li>Some other thread {@linkplain Thread#interrupt interrupts} * the current thread. * </ul> * * <p>If the current thread: * <ul> * <li>has its interrupted status set on entry to this method; or * <li>is {@linkplain Thread#interrupt interrupted} while waiting * for a permit, * </ul> * then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * * @throws InterruptedException if the current thread is interrupted */ publicvoidacquire()throws InterruptedException { sync.acquireSharedInterruptibly(1); }
/** * Acquires the given number of permits from this semaphore, * blocking until all are available, * or the thread is {@linkplain Thread#interrupt interrupted}. * * <p>Acquires the given number of permits, if they are available, * and returns immediately, reducing the number of available permits * by the given amount. * * <p>If insufficient permits are available then the current thread becomes * disabled for thread scheduling purposes and lies dormant until * one of two things happens: * <ul> * <li>Some other thread invokes one of the {@link #release() release} * methods for this semaphore, the current thread is next to be assigned * permits and the number of available permits satisfies this request; or * <li>Some other thread {@linkplain Thread#interrupt interrupts} * the current thread. * </ul> * * <p>If the current thread: * <ul> * <li>has its interrupted status set on entry to this method; or * <li>is {@linkplain Thread#interrupt interrupted} while waiting * for a permit, * </ul> * then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * Any permits that were to be assigned to this thread are instead * assigned to other threads trying to acquire permits, as if * permits had been made available by a call to {@link #release()}. * * @param permits the number of permits to acquire * @throws InterruptedException if the current thread is interrupted * @throws IllegalArgumentException if {@code permits} is negative */ publicvoidacquire(intpermits)throws InterruptedException { if (permits < 0) thrownewIllegalArgumentException(); sync.acquireSharedInterruptibly(permits); }
4.3 release
释放一个许可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * Releases a permit, returning it to the semaphore. * * <p>Releases a permit, increasing the number of available permits by * one. If any threads are trying to acquire a permit, then one is * selected and given the permit that was just released. That thread * is (re)enabled for thread scheduling purposes. * * <p>There is no requirement that a thread that releases a permit must * have acquired that permit by calling {@link #acquire}. * Correct usage of a semaphore is established by programming convention * in the application. */ publicvoidrelease() { sync.releaseShared(1); }
/** * Releases the given number of permits, returning them to the semaphore. * * <p>Releases the given number of permits, increasing the number of * available permits by that amount. * If any threads are trying to acquire permits, then one * is selected and given the permits that were just released. * If the number of available permits satisfies that thread's request * then that thread is (re)enabled for thread scheduling purposes; * otherwise the thread will wait until sufficient permits are available. * If there are still permits available * after this thread's request has been satisfied, then those permits * are assigned in turn to other threads trying to acquire permits. * * <p>There is no requirement that a thread that releases a permit must * have acquired that permit by calling {@link Semaphore#acquire acquire}. * Correct usage of a semaphore is established by programming convention * in the application. * * @param permits the number of permits to release * @throws IllegalArgumentException if {@code permits} is negative */ publicvoidrelease(intpermits) { if (permits < 0) thrownewIllegalArgumentException(); sync.releaseShared(permits); }