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