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