001    /*
002     * $Id: Terminator.java 3393 2010-12-09 21:46:03Z kredel $
003     */
004    
005    package edu.jas.util;
006    
007    
008    import java.util.concurrent.Semaphore;
009    
010    import org.apache.log4j.Logger;
011    
012    
013    //import edu.unima.ky.parallel.Semaphore;
014    
015    /**
016     * Terminating helper class. Like a barrier, but with coming and going.
017     * @author Heinz Kredel
018     */
019    
020    public class Terminator {
021    
022    
023        private static final Logger logger = Logger.getLogger(Terminator.class);
024    
025    
026        private final int workers;
027    
028    
029        private int idler = 0;
030    
031    
032        private final Semaphore fin;
033    
034    
035        private /*volatile*/ boolean done;
036    
037    
038        /**
039         * Terminator.
040         * @param workers number of expected threads.
041         */
042        public Terminator(int workers) {
043            this.workers = workers;
044            fin = new Semaphore(0);
045            done = false;
046            logger.info("constructor, workers = " + workers);
047        }
048    
049    
050        /**
051         * to string
052         */
053        @Override
054        public String toString() {
055            return "Terminator(" + done + ",workers=" + workers + ",idler=" + idler + ")";
056        }
057    
058    
059        /**
060         * beIdle.
061         * Checks for release().
062         */
063        public synchronized void beIdle() {
064            idler++;
065            logger.info("beIdle, idler = " + idler);
066            if (idler >= workers) {
067                done = true;
068                fin.release(); //fin.V();
069            }
070        }
071    
072    
073        /**
074         * initIdle.
075         * No check for release().
076         * @param i number of idle threads.
077         */
078        public synchronized void initIdle(int i) {
079            idler += i;
080            logger.info("initIdle, idler = " + idler);
081            if ( idler > workers ) {
082                if (done) {
083                    idler = workers;
084                } else {
085                    throw new RuntimeException("idler > workers");
086                }
087            }
088        }
089    
090    
091        /**
092         * beIdle.
093         * Checks for release().
094         * @param i number of idle threads.
095         */
096        public synchronized void beIdle(int i) {
097            idler += i;
098            logger.info("beIdle, idler = " + idler);
099            if (idler >= workers) {
100                done = true;
101                fin.release(); //fin.V();
102            }
103        }
104    
105    
106        /**
107         * allIdle.
108         * Checks for release().
109         */
110        public synchronized void allIdle() {
111            idler = workers;
112            logger.info("allIdle");
113            done = true;
114            fin.release(); //fin.V();
115        }
116    
117    
118        /**
119         * notIdle.
120         */
121        public synchronized void notIdle() {
122            idler--;
123            logger.info("notIdle, idler = " + idler);
124            if ( idler < 0 ) {
125                throw new RuntimeException("idler < 0");
126            }
127        }
128    
129    
130        /**
131         * getJobs.
132         * @return number of possible jobs.
133         */
134        public synchronized int getJobs() {
135            return (workers - idler);
136        }
137    
138    
139        /**
140         * hasJobs.
141         * @return true, if there are possibly jobs, else false.
142         */
143        public boolean hasJobs() {
144            return (idler < workers);
145        }
146    
147    
148        /**
149         * Release if possible.
150         */
151        public synchronized void release() {
152            logger.info("release = " + this);
153            if ( idler >= workers ) {
154                done = true;
155                fin.release(); 
156            }
157            //logger.info("release, idler = " + idler);
158        }
159    
160    
161        /**
162         * Wait until released.
163         */
164        public void waitDone() {
165            try {
166                fin.acquire(); 
167            } catch (InterruptedException e) {
168                Thread.currentThread().interrupt();
169            }
170            logger.info("waitDone " + this);
171        }
172    
173    }