package uk.co.mmscomputing.concurrent; /* Thread- und Netzwerk-Programmierung mit Java ISBN 3-89864-133-3 */ /* In order to be 'compatible' with Sun's new java.util.concurrent package in 1.5.0 I changed this package constructor => fairness parameter is always true down => acquire up => release */ public class Semaphore extends Object{ private int initpermits; // initially available permits private int available; // currently available permits private int waiting; // threads that currently are waiting public Semaphore(int permits, boolean fair) { // Use always fair=true initpermits=permits; // Sun allows negative permit values available=initpermits; waiting=0; } public boolean isFair(){return true;} // always true; This implementation is only 'weakly fair' public int availablePermits(){return available;} /* protected void finalize() throws Throwable{ if(available!=initpermits){ int x=available-initpermits; // threads that haven't been released yet. System.err.println("Semaphore : "+x+" pending operations."); } super.finalize(); } */ public synchronized void acquire()throws InterruptedException{ while(available<=0){ // if no permits are available try{ waiting++; // thread is now waiting wait(); // wait until notified }finally{ waiting--; // thread is not waiting anymore } } available--; // got a permit, decrease available permits } public synchronized boolean tryAcquire(long timeout,TimeUnit unit)throws InterruptedException{ if(available<=0){ // if no permits are available if(timeout<=0){return false;} // if time is not positive return immediatly try{ waiting++; // wait only once; neglect "spurious wakeups" here wait(timeout); // wait until notified or timed out (timeout in MILLISECONDS) }finally{ waiting--; // thread is not waiting anymore } if(available<=0){return false;} // still nothing available } available--; // got a permit, decrease available permits return true; } public synchronized void release(){ available++; // release a permit, increase available permits if((available>0)&&(waiting>0)){ // if init permits < 0 we need to just count up first notify(); } } public void release(int permits){ for(int i=0;i<permits;i++){ release(); } } /* public void releaseAll(){ while(waiting>0){ release(); } } */ }