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