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