Annotation of java/classes/org/w3c/util/ThreadCache.java, revision 1.5
1.5 ! abaird 1: // ThreadCache.java
! 2: // $Id$
! 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 {
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:
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);
39: to = true;
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:
55: synchronized void wakeup(Runnable runnable) {
56: runner = runnable;
57: notify();
58: }
59:
60: public void run() {
61: try {
62: while ( true ) {
63: // Wait for a runner:
64: Runnable torun = waitForRunner();
65: // If dead, stop
66: if ( ! alive )
67: break;
68: // If runner, run:
69: if ( torun != null )
70: torun.run();
71: }
72: } finally {
73: cache.isDead(this);
74: }
75: }
76:
77: void start(Runnable runnable) {
78: this.runner = runnable;
79: start();
80: }
81:
1.3 abaird 82: CachedThread(ThreadCache cache, int id) {
83: super(cache.getThreadGroup(), cache.getThreadGroup().getName()+":"+id);
1.1 abaird 84: this.cache = cache;
1.2 abaird 85: setPriority(cache.getThreadPriority());
86: setDaemon(true);
1.1 abaird 87: }
88:
89: }
90:
91: public class ThreadCache {
1.2 abaird 92: private static final boolean debug = false;
93:
1.1 abaird 94: /**
95: * Default number of cached threads.
96: */
97: private static final int DEFAULT_CACHESIZE = 5;
98: /**
1.2 abaird 99: * Has this thread cache been initialized ?
100: */
101: protected boolean inited = false;
102: /**
1.1 abaird 103: * The thread group for this thread cache.
104: */
105: protected ThreadGroup group = null;
106: /**
107: * Number of cached threads.
108: */
109: protected int cachesize = DEFAULT_CACHESIZE;
110: /**
111: * Number of created threads.
112: */
113: protected int threadcount = 0;
114: /**
1.3 abaird 115: * Uniq thread identifier within this ThreadCache instance.
116: */
117: protected int threadid = 0;
118: /**
1.2 abaird 119: * Number of idle threads to always maintain alive.
120: */
121: protected int idlethreads = 0;
122: /**
1.1 abaird 123: * Should we queue thread requests, rather then creating new threads.
124: */
125: protected boolean growasneeded = false;
126: /**
127: * List of free threads.
128: */
129: protected CachedThread freelist = null;
130: /**
131: * List of buzy threads.
132: */
133: protected CachedThread buzylist = null;
1.2 abaird 134: /**
135: * The idle timeout, for a thread to wait before being killed.
136: * Defaults to <strong>5000</strong> milliseconds.
137: */
138: protected int idletimeout = 5000;
139: /**
140: * Cached thread priority.
141: */
142: protected int threadpriority = 5;
143:
144: /**
145: * Get the idle timeout value for this cache.
146: * @return The idletimeout value, or negative if no timeout applies.
147: */
148:
149: synchronized final int getIdleTimeout() {
150: return (threadcount <= idlethreads) ? -1 : idletimeout;
151: }
1.1 abaird 152:
153: /**
154: * The given thread is about to be declared free.
1.4 abaird 155: * @return A boolean, <strong>true</strong> if the thread is to continue
1.1 abaird 156: * running, <strong>false</strong> if the thread should stop.
157: */
158:
1.2 abaird 159: final synchronized boolean isFree(CachedThread t, boolean timedout) {
160: if ( timedout && (threadcount > idlethreads) ) {
1.4 abaird 161: if ( ! t.isTerminated() ) {
1.2 abaird 162: threadcount--;
1.4 abaird 163: notifyAll();
164: }
1.2 abaird 165: return false;
166: } else if ( threadcount < cachesize ) {
1.1 abaird 167: t.next = freelist;
168: freelist = t;
169: notifyAll();
170: return true;
171: } else {
1.4 abaird 172: if ( ! t.isTerminated() ) {
1.2 abaird 173: threadcount--;
1.4 abaird 174: notifyAll();
175: }
1.1 abaird 176: return false;
177: }
178: }
179:
180: /**
181: * The given thread has terminated, cleanup any associated state.
182: * @param dead The dead CachedThread instance.
183: */
184:
185: final synchronized void isDead(CachedThread t) {
1.2 abaird 186: if ( debug )
187: System.out.println("** "+t+": is dead tc="+threadcount);
1.4 abaird 188: if ( ! t.isTerminated() ) {
1.2 abaird 189: threadcount--;
1.4 abaird 190: notifyAll();
191: }
1.1 abaird 192: }
193:
194: /**
195: * Create a new thread within this thread cache.
196: * @return A new CachedThread instance.
197: */
198:
199: private synchronized CachedThread createThread() {
200: threadcount++;
1.3 abaird 201: threadid++;
202: return new CachedThread(this, threadid);
1.1 abaird 203: }
204:
205: /**
206: * Allocate a new thread, as requested.
207: * @return A CachedThread instance, or <strong>null</strong> if unable to
208: * allocate a new thread.
209: */
210:
211: protected synchronized CachedThread allocateThread(boolean waitp) {
212: CachedThread t = null;
213: while ( true ) {
214: if ( freelist != null ) {
1.4 abaird 215: if ( debug )
216: System.out.println("*** allocateThread: free thread");
1.1 abaird 217: t = freelist;
218: freelist = freelist.next;
219: break;
220: } else if ((threadcount < cachesize) || growasneeded) {
1.4 abaird 221: if ( debug )
222: System.out.println("*** create new thread.");
1.1 abaird 223: t = createThread();
1.2 abaird 224: t.start();
1.1 abaird 225: break;
226: } else if ( waitp ) {
1.4 abaird 227: if ( debug )
228: System.out.println("*** wait for a thread.");
1.1 abaird 229: // Wait for a thread to become available
230: try {
231: wait();
232: } catch (InterruptedException ex) {
233: }
234: } else {
235: return null;
236: }
237: }
1.2 abaird 238: // We are about to return a thread, mark it buzy:
1.1 abaird 239: t.next = buzylist;
240: buzylist = t;
241: return t;
242: }
243:
244: /**
1.2 abaird 245: * Set the thread cache size.
246: * This will also update the number of idle threads to maintain, if
247: * requested.
248: * @param cachesize The new thread cache size.
249: * @param update If <strong>true</strong> also update the number of
250: * threads to maintain idle.
251: */
252:
253: public synchronized void setCachesize(int cachesize, boolean update) {
254: this.cachesize = cachesize;
255: if ( update )
1.3 abaird 256: this.idlethreads = (cachesize>>1);
1.2 abaird 257: }
258:
259: /**
260: * Set the thread cache size.
261: * Updaet the number of idle threads to keep alive.
262: * @param cachesize The new thread cache size.
263: */
264:
265: public void setCachesize(int cachesize) {
266: setCachesize(cachesize, true);
267: }
268:
269: /**
1.5 ! abaird 270: * Enable/disable the thread cache to grow as needed.
! 271: * This flag should be turned on only if always getting a thread as fast
! 272: * as possible is critical.
! 273: * @param onoff The toggle.
! 274: */
! 275:
! 276: public void setGrowAsNeeded(boolean onoff) {
! 277: this.growasneeded = onoff;
! 278: }
! 279:
! 280: /**
1.2 abaird 281: * Set all the cached threads priority.
282: * Changing the cached thread priority should be done before the thread
283: * cache is initialized, it will <em>not</em> affect already created
284: * threads.
285: * @param priority The new cachewd threads priority.
286: */
287:
288: public void setThreadPriority(int priority) {
289: threadpriority = priority;
290: }
291:
292: /**
293: * Get the cached thread normal priority.
294: * @return Currently assigned cached thread priority.
295: */
296:
297: public int getThreadPriority() {
298: return threadpriority;
299: }
300:
301: /**
1.3 abaird 302: * Set the idle timeout.
303: * The idle timeout value is used to eliminate threads that have remain
304: * idle for too long (although the thread cache will ensure that a
305: * decent minimal number of threads stay around).
306: * @param idletimeout The new idle timeout.
307: */
308:
309: public synchronized void setIdleTimeout(int idletimeout) {
310: this.idletimeout = idletimeout;
311: }
312:
313: /**
1.1 abaird 314: * Request a thread to run on the given object.
315: * @param runnable The object to run with the allocated thread.
316: * @param waitp If <strong>true</strong> wait until a free thread is
317: * available, otherwise, return <strong>false</strong>.
318: * @return A boolean, <strong>true</strong> if a thread was successfully
319: * allocated for the given object, <strong>false</strong> otherwise.
320: */
321:
322: public boolean getThread(Runnable runnable, boolean waitp) {
1.4 abaird 323: if ( debug )
324: System.out.println("*** getting a thread for "+runnable);
1.2 abaird 325: if ( ! inited )
326: throw new RuntimeException("Uninitialized thread cache");
1.1 abaird 327: CachedThread t = allocateThread(waitp);
328: if ( t != null ) {
329: t.wakeup(runnable);
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