Annotation of java/classes/org/w3c/util/ThreadCache.java, revision 1.8
1.5 abaird 1: // ThreadCache.java
1.8 ! abaird 2: // $Id: ThreadCache.java,v 1.7 1997/03/10 16:11:08 abaird Exp $
1.5 abaird 3: // (c) COPYRIGHT MIT and INRIA, 1996-1997.
4: // Please first read the full copyright statement in file COPYRIGHT.html
5:
1.1 abaird 6: package w3c.util;
7:
8: class CachedThread extends Thread {
1.6 abaird 9: Runnable runner = null;
10: boolean alive = true;
11: ThreadCache cache = null;
12: CachedThread next = null;
1.2 abaird 13: boolean terminated = false;
1.8 ! abaird 14: boolean started = false;
1.2 abaird 15:
16: synchronized boolean isTerminated() {
17: boolean ret = terminated;
18: terminated = true;
19: return ret;
20: }
21:
1.1 abaird 22: synchronized Runnable waitForRunner() {
1.2 abaird 23: boolean to = false;
24:
1.1 abaird 25: while ( alive ) {
26: // Is a runner available ?
27: if ( runner != null ) {
28: Runnable torun = runner;
29: runner = null;
30: return torun;
1.2 abaird 31: }
1.1 abaird 32: // Notify the cache that we are free, and continue if allowed:
1.2 abaird 33: if ( alive = cache.isFree(this, to) ) {
1.1 abaird 34: try {
1.2 abaird 35: int idleto = cache.getIdleTimeout();
36: to = false;
37: if ( idleto > 0 ) {
38: wait(idleto);
1.8 ! abaird 39: to = (runner == null);
1.2 abaird 40: } else {
41: wait();
42: }
1.1 abaird 43: } catch (InterruptedException ex) {
44: }
45: }
46: }
47: return null;
48: }
49:
50: synchronized void kill() {
51: alive = false;
52: notify();
53: }
54:
1.8 ! abaird 55: synchronized boolean wakeup(Runnable runnable) {
! 56: if ( alive ) {
! 57: System.out.println("*** "+runnable+" warm up "+this+" "+alive);
! 58: runner = runnable;
! 59: if ( ! started )
! 60: this.start();
! 61: notify();
! 62: return true;
! 63: } else {
! 64: return false;
! 65: }
1.1 abaird 66: }
67:
1.8 ! abaird 68: public synchronized void start() {
! 69: super.start();
! 70: this.started = true;
! 71: }
! 72:
1.1 abaird 73: public void run() {
74: try {
75: while ( true ) {
76: // Wait for a runner:
77: Runnable torun = waitForRunner();
1.8 ! abaird 78: // If runner, run:
! 79: if ( torun != null )
! 80: torun.run();
1.1 abaird 81: // If dead, stop
82: if ( ! alive )
83: break;
84: }
85: } finally {
86: cache.isDead(this);
87: }
88: }
89:
1.3 abaird 90: CachedThread(ThreadCache cache, int id) {
91: super(cache.getThreadGroup(), cache.getThreadGroup().getName()+":"+id);
1.1 abaird 92: this.cache = cache;
1.2 abaird 93: setPriority(cache.getThreadPriority());
94: setDaemon(true);
1.1 abaird 95: }
96:
97: }
98:
99: public class ThreadCache {
1.2 abaird 100: private static final boolean debug = false;
101:
1.1 abaird 102: /**
103: * Default number of cached threads.
104: */
105: private static final int DEFAULT_CACHESIZE = 5;
106: /**
1.2 abaird 107: * Has this thread cache been initialized ?
108: */
109: protected boolean inited = false;
110: /**
1.1 abaird 111: * The thread group for this thread cache.
112: */
113: protected ThreadGroup group = null;
114: /**
115: * Number of cached threads.
116: */
117: protected int cachesize = DEFAULT_CACHESIZE;
118: /**
119: * Number of created threads.
120: */
121: protected int threadcount = 0;
122: /**
1.3 abaird 123: * Uniq thread identifier within this ThreadCache instance.
124: */
125: protected int threadid = 0;
126: /**
1.2 abaird 127: * Number of idle threads to always maintain alive.
128: */
129: protected int idlethreads = 0;
130: /**
1.1 abaird 131: * Should we queue thread requests, rather then creating new threads.
132: */
133: protected boolean growasneeded = false;
134: /**
135: * List of free threads.
136: */
137: protected CachedThread freelist = null;
138: /**
139: * List of buzy threads.
140: */
141: protected CachedThread buzylist = null;
1.2 abaird 142: /**
143: * The idle timeout, for a thread to wait before being killed.
144: * Defaults to <strong>5000</strong> milliseconds.
145: */
146: protected int idletimeout = 5000;
147: /**
148: * Cached thread priority.
149: */
150: protected int threadpriority = 5;
151:
152: /**
153: * Get the idle timeout value for this cache.
154: * @return The idletimeout value, or negative if no timeout applies.
155: */
156:
157: synchronized final int getIdleTimeout() {
158: return (threadcount <= idlethreads) ? -1 : idletimeout;
159: }
1.1 abaird 160:
161: /**
162: * The given thread is about to be declared free.
1.4 abaird 163: * @return A boolean, <strong>true</strong> if the thread is to continue
1.1 abaird 164: * running, <strong>false</strong> if the thread should stop.
165: */
166:
1.2 abaird 167: final synchronized boolean isFree(CachedThread t, boolean timedout) {
168: if ( timedout && (threadcount > idlethreads) ) {
1.4 abaird 169: if ( ! t.isTerminated() ) {
1.2 abaird 170: threadcount--;
1.4 abaird 171: notifyAll();
172: }
1.2 abaird 173: return false;
174: } else if ( threadcount < cachesize ) {
1.1 abaird 175: t.next = freelist;
176: freelist = t;
177: notifyAll();
178: return true;
179: } else {
1.4 abaird 180: if ( ! t.isTerminated() ) {
1.2 abaird 181: threadcount--;
1.4 abaird 182: notifyAll();
183: }
1.1 abaird 184: return false;
185: }
186: }
187:
188: /**
189: * The given thread has terminated, cleanup any associated state.
190: * @param dead The dead CachedThread instance.
191: */
192:
193: final synchronized void isDead(CachedThread t) {
1.2 abaird 194: if ( debug )
195: System.out.println("** "+t+": is dead tc="+threadcount);
1.4 abaird 196: if ( ! t.isTerminated() ) {
1.2 abaird 197: threadcount--;
1.4 abaird 198: notifyAll();
199: }
1.1 abaird 200: }
201:
202: /**
203: * Create a new thread within this thread cache.
204: * @return A new CachedThread instance.
205: */
206:
207: private synchronized CachedThread createThread() {
208: threadcount++;
1.3 abaird 209: threadid++;
210: return new CachedThread(this, threadid);
1.1 abaird 211: }
212:
213: /**
214: * Allocate a new thread, as requested.
215: * @return A CachedThread instance, or <strong>null</strong> if unable to
216: * allocate a new thread.
217: */
218:
219: protected synchronized CachedThread allocateThread(boolean waitp) {
220: CachedThread t = null;
221: while ( true ) {
222: if ( freelist != null ) {
1.4 abaird 223: if ( debug )
224: System.out.println("*** allocateThread: free thread");
1.1 abaird 225: t = freelist;
226: freelist = freelist.next;
227: break;
228: } else if ((threadcount < cachesize) || growasneeded) {
1.4 abaird 229: if ( debug )
230: System.out.println("*** create new thread.");
1.1 abaird 231: t = createThread();
232: break;
233: } else if ( waitp ) {
1.4 abaird 234: if ( debug )
235: System.out.println("*** wait for a thread.");
1.1 abaird 236: // Wait for a thread to become available
237: try {
238: wait();
239: } catch (InterruptedException ex) {
240: }
241: } else {
242: return null;
243: }
244: }
1.2 abaird 245: // We are about to return a thread, mark it buzy:
1.1 abaird 246: t.next = buzylist;
247: buzylist = t;
248: return t;
249: }
250:
251: /**
1.2 abaird 252: * Set the thread cache size.
253: * This will also update the number of idle threads to maintain, if
254: * requested.
255: * @param cachesize The new thread cache size.
256: * @param update If <strong>true</strong> also update the number of
257: * threads to maintain idle.
258: */
259:
260: public synchronized void setCachesize(int cachesize, boolean update) {
261: this.cachesize = cachesize;
262: if ( update )
1.3 abaird 263: this.idlethreads = (cachesize>>1);
1.2 abaird 264: }
265:
266: /**
267: * Set the thread cache size.
268: * Updaet the number of idle threads to keep alive.
269: * @param cachesize The new thread cache size.
270: */
271:
272: public void setCachesize(int cachesize) {
273: setCachesize(cachesize, true);
274: }
275:
276: /**
1.5 abaird 277: * Enable/disable the thread cache to grow as needed.
278: * This flag should be turned on only if always getting a thread as fast
279: * as possible is critical.
280: * @param onoff The toggle.
281: */
282:
283: public void setGrowAsNeeded(boolean onoff) {
284: this.growasneeded = onoff;
285: }
286:
287: /**
1.2 abaird 288: * Set all the cached threads priority.
289: * Changing the cached thread priority should be done before the thread
290: * cache is initialized, it will <em>not</em> affect already created
291: * threads.
292: * @param priority The new cachewd threads priority.
293: */
294:
295: public void setThreadPriority(int priority) {
296: threadpriority = priority;
297: }
298:
299: /**
300: * Get the cached thread normal priority.
301: * @return Currently assigned cached thread priority.
302: */
303:
304: public int getThreadPriority() {
305: return threadpriority;
306: }
307:
308: /**
1.3 abaird 309: * Set the idle timeout.
310: * The idle timeout value is used to eliminate threads that have remain
311: * idle for too long (although the thread cache will ensure that a
312: * decent minimal number of threads stay around).
313: * @param idletimeout The new idle timeout.
314: */
315:
316: public synchronized void setIdleTimeout(int idletimeout) {
317: this.idletimeout = idletimeout;
318: }
319:
320: /**
1.1 abaird 321: * Request a thread to run on the given object.
322: * @param runnable The object to run with the allocated thread.
323: * @param waitp If <strong>true</strong> wait until a free thread is
324: * available, otherwise, return <strong>false</strong>.
325: * @return A boolean, <strong>true</strong> if a thread was successfully
326: * allocated for the given object, <strong>false</strong> otherwise.
327: */
328:
329: public boolean getThread(Runnable runnable, boolean waitp) {
1.4 abaird 330: if ( debug )
331: System.out.println("*** getting a thread for "+runnable);
1.2 abaird 332: if ( ! inited )
333: throw new RuntimeException("Uninitialized thread cache");
1.8 ! abaird 334: // We have to loop here:
! 335: while ( true ) {
! 336: CachedThread t = allocateThread(waitp);
! 337: if ( t != null ) {
! 338: if ( t.wakeup(runnable) )
! 339: return true;
! 340: } else {
! 341: if ( debug )
! 342: System.out.println("*** no thread avail for "+runnable);
! 343: return false;
! 344: }
1.1 abaird 345: }
1.3 abaird 346: }
347:
348: /**
349: * Get the ThreadGroup managed by this ThreadCache instance.
350: * @return A ThreadGroup instance.
351: */
352:
353: public ThreadGroup getThreadGroup() {
354: return group;
1.1 abaird 355: }
356:
357: /**
1.2 abaird 358: * Initialize the given thread cache.
359: * This two stage initialize method is done so that configuration
360: * of the thread cache can be done before any thread get actually
361: * created.
362: */
363:
364: public synchronized void initialize() {
365: for (int i = 0 ; i < idlethreads ; i++)
366: createThread().start();
367: inited = true;
368: }
369:
370: /**
1.1 abaird 371: * Create a thread cache, whose threads are to be children of the group.
372: * @param group The thread group to which this thread cache is bound.
373: * @param nstart Number of thread to create in advance.
374: */
375:
1.2 abaird 376: public ThreadCache(ThreadGroup group) {
1.1 abaird 377: this.group = group;
378: }
379:
380: /**
381: * Create a thread cache, after creating a new thread group.
382: * @param name The name of the thread group to create.
383: */
384:
385: public ThreadCache(String name) {
1.2 abaird 386: this(new ThreadGroup(name));
1.1 abaird 387: }
388:
389: /**
390: * Create a thread cache, after creating a new thread group.
391: * @param parent The parent of the thread group to create.
392: * @param name The name of the thread group.
393: */
394:
395: public ThreadCache(ThreadGroup parent, String name) {
1.2 abaird 396: this(new ThreadGroup(parent, name));
1.1 abaird 397: }
398:
399: }
Webmaster