001/*
002 * $Id: Terminator.java 3979 2012-07-09 21:13:53Z 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 = 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 synchronized 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}