Annotation of java/classes/org/w3c/util/ThreadCache.java, revision 1.6
1.5 abaird 1: // ThreadCache.java
1.6 ! abaird 2: // $Id: ThreadCache.java,v 1.5 1997/01/17 10:11:09 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.6 ! abaird 14: boolean firsttime = true;
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 ) {
1.6 ! abaird 26: // The firstime, make sure we really run on something:
! 27: while ( firsttime && (runner == null) ) {
! 28: try {
! 29: wait();
! 30: } catch (InterruptedException ex) {
! 31: }
! 32: }
! 33: firsttime = false;
1.1 abaird 34: // Is a runner available ?
35: if ( runner != null ) {
36: Runnable torun = runner;
37: runner = null;
38: return torun;
1.2 abaird 39: }
1.1 abaird 40: // Notify the cache that we are free, and continue if allowed:
1.2 abaird 41: if ( alive = cache.isFree(this, to) ) {
1.1 abaird 42: try {
1.2 abaird 43: int idleto = cache.getIdleTimeout();
44: to = false;
45: if ( idleto > 0 ) {
46: wait(idleto);
47: to = true;
48: } else {
49: wait();
50: }
1.1 abaird 51: } catch (InterruptedException ex) {
52: }
53: }
54: }
55: return null;
56: }
57:
58: synchronized void kill() {
59: alive = false;
60: notify();
61: }
62:
63: synchronized void wakeup(Runnable runnable) {
64: runner = runnable;
65: notify();
66: }
67:
68: public void run() {
69: try {
70: while ( true ) {
71: // Wait for a runner:
72: Runnable torun = waitForRunner();
73: // If dead, stop
74: if ( ! alive )
75: break;
76: // If runner, run:
77: if ( torun != null )
78: torun.run();
79: }
80: } finally {
81: cache.isDead(this);
82: }
83: }
84:
85: void start(Runnable runnable) {
86: this.runner = runnable;
87: start();
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();
1.2 abaird 232: t.start();
1.1 abaird 233: break;
234: } else if ( waitp ) {
1.4 abaird 235: if ( debug )
236: System.out.println("*** wait for a thread.");
1.1 abaird 237: // Wait for a thread to become available
238: try {
239: wait();
240: } catch (InterruptedException ex) {
241: }
242: } else {
243: return null;
244: }
245: }
1.2 abaird 246: // We are about to return a thread, mark it buzy:
1.1 abaird 247: t.next = buzylist;
248: buzylist = t;
249: return t;
250: }
251:
252: /**
1.2 abaird 253: * Set the thread cache size.
254: * This will also update the number of idle threads to maintain, if
255: * requested.
256: * @param cachesize The new thread cache size.
257: * @param update If <strong>true</strong> also update the number of
258: * threads to maintain idle.
259: */
260:
261: public synchronized void setCachesize(int cachesize, boolean update) {
262: this.cachesize = cachesize;
263: if ( update )
1.3 abaird 264: this.idlethreads = (cachesize>>1);
1.2 abaird 265: }
266:
267: /**
268: * Set the thread cache size.
269: * Updaet the number of idle threads to keep alive.
270: * @param cachesize The new thread cache size.
271: */
272:
273: public void setCachesize(int cachesize) {
274: setCachesize(cachesize, true);
275: }
276:
277: /**
1.5 abaird 278: * Enable/disable the thread cache to grow as needed.
279: * This flag should be turned on only if always getting a thread as fast
280: * as possible is critical.
281: * @param onoff The toggle.
282: */
283:
284: public void setGrowAsNeeded(boolean onoff) {
285: this.growasneeded = onoff;
286: }
287:
288: /**
1.2 abaird 289: * Set all the cached threads priority.
290: * Changing the cached thread priority should be done before the thread
291: * cache is initialized, it will <em>not</em> affect already created
292: * threads.
293: * @param priority The new cachewd threads priority.
294: */
295:
296: public void setThreadPriority(int priority) {
297: threadpriority = priority;
298: }
299:
300: /**
301: * Get the cached thread normal priority.
302: * @return Currently assigned cached thread priority.
303: */
304:
305: public int getThreadPriority() {
306: return threadpriority;
307: }
308:
309: /**
1.3 abaird 310: * Set the idle timeout.
311: * The idle timeout value is used to eliminate threads that have remain
312: * idle for too long (although the thread cache will ensure that a
313: * decent minimal number of threads stay around).
314: * @param idletimeout The new idle timeout.
315: */
316:
317: public synchronized void setIdleTimeout(int idletimeout) {
318: this.idletimeout = idletimeout;
319: }
320:
321: /**
1.1 abaird 322: * Request a thread to run on the given object.
323: * @param runnable The object to run with the allocated thread.
324: * @param waitp If <strong>true</strong> wait until a free thread is
325: * available, otherwise, return <strong>false</strong>.
326: * @return A boolean, <strong>true</strong> if a thread was successfully
327: * allocated for the given object, <strong>false</strong> otherwise.
328: */
329:
330: public boolean getThread(Runnable runnable, boolean waitp) {
1.4 abaird 331: if ( debug )
332: System.out.println("*** getting a thread for "+runnable);
1.2 abaird 333: if ( ! inited )
334: throw new RuntimeException("Uninitialized thread cache");
1.1 abaird 335: CachedThread t = allocateThread(waitp);
336: if ( t != null ) {
337: t.wakeup(runnable);
338: return true;
339: } else {
1.2 abaird 340: if ( debug )
341: System.out.println("*** no thread available for "+runnable);
1.1 abaird 342: return false;
343: }
1.3 abaird 344: }
345:
346: /**
347: * Get the ThreadGroup managed by this ThreadCache instance.
348: * @return A ThreadGroup instance.
349: */
350:
351: public ThreadGroup getThreadGroup() {
352: return group;
1.1 abaird 353: }
354:
355: /**
1.2 abaird 356: * Initialize the given thread cache.
357: * This two stage initialize method is done so that configuration
358: * of the thread cache can be done before any thread get actually
359: * created.
360: */
361:
362: public synchronized void initialize() {
363: for (int i = 0 ; i < idlethreads ; i++)
364: createThread().start();
365: inited = true;
366: }
367:
368: /**
1.1 abaird 369: * Create a thread cache, whose threads are to be children of the group.
370: * @param group The thread group to which this thread cache is bound.
371: * @param nstart Number of thread to create in advance.
372: */
373:
1.2 abaird 374: public ThreadCache(ThreadGroup group) {
1.1 abaird 375: this.group = group;
376: }
377:
378: /**
379: * Create a thread cache, after creating a new thread group.
380: * @param name The name of the thread group to create.
381: */
382:
383: public ThreadCache(String name) {
1.2 abaird 384: this(new ThreadGroup(name));
1.1 abaird 385: }
386:
387: /**
388: * Create a thread cache, after creating a new thread group.
389: * @param parent The parent of the thread group to create.
390: * @param name The name of the thread group.
391: */
392:
393: public ThreadCache(ThreadGroup parent, String name) {
1.2 abaird 394: this(new ThreadGroup(parent, name));
1.1 abaird 395: }
396:
397: }
Webmaster