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