001/*
002 * $Id: Terminator.java 4543 2013-07-30 12:24:09Z kredel $
003 */
004
005package edu.jas.util;
006
007
008import java.util.concurrent.Semaphore;
009
010import 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
020public 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;
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        idler = 0;
047        logger.info("constructor, workers = " + workers);
048    }
049
050
051    /**
052     * to string
053     */
054    @Override
055    public String toString() {
056        return "Terminator(" + done + ",workers=" + workers + ",idler=" + idler + ")";
057    }
058
059
060    /**
061     * beIdle.
062     * Checks for release().
063     */
064    public synchronized void beIdle() {
065        idler++;
066        logger.info("beIdle, idler = " + idler);
067        if (idler >= workers) {
068            done = true;
069            fin.release(); //fin.V();
070        }
071    }
072
073
074    /**
075     * initIdle.
076     * No check for release().
077     * @param i number of idle threads.
078     */
079    public synchronized void initIdle(int i) {
080        idler += i;
081        logger.info("initIdle, idler = " + idler);
082        if ( idler > workers ) {
083            if (done) {
084                idler = workers;
085            } else {
086                throw new RuntimeException("idler > workers");
087            }
088        }
089    }
090
091
092    /**
093     * beIdle.
094     * Checks for release().
095     * @param i number of idle threads.
096     */
097    public synchronized void beIdle(int i) {
098        idler += i;
099        logger.info("beIdle, idler = " + idler);
100        if (idler >= workers) {
101            done = true;
102            fin.release(); //fin.V();
103        }
104    }
105
106
107    /**
108     * allIdle.
109     * Checks for release().
110     */
111    public synchronized void allIdle() {
112        idler = workers;
113        logger.info("allIdle");
114        done = true;
115        fin.release(); //fin.V();
116    }
117
118
119    /**
120     * notIdle.
121     */
122    public synchronized void notIdle() {
123        idler--;
124        logger.info("notIdle, idler = " + idler);
125        if ( idler < 0 ) {
126            throw new RuntimeException("idler < 0");
127        }
128    }
129
130
131    /**
132     * getJobs.
133     * @return number of possible jobs.
134     */
135    public synchronized int getJobs() {
136        return (workers - idler);
137    }
138
139
140    /**
141     * hasJobs.
142     * @return true, if there are possibly jobs, else false.
143     */
144    public synchronized boolean hasJobs() {
145        return (idler < workers);
146    }
147
148
149    /**
150     * Release if possible.
151     */
152    public synchronized void release() {
153        logger.info("release = " + this);
154        if ( idler >= workers ) {
155            done = true;
156            fin.release(); 
157        }
158        //logger.info("release, idler = " + idler);
159    }
160
161
162    /**
163     * Wait until released.
164     */
165    public void waitDone() {
166        try {
167            fin.acquire(); 
168        } catch (InterruptedException e) {
169            Thread.currentThread().interrupt();
170        }
171        logger.info("waitDone " + this);
172    }
173
174}