Annotation of java/classes/org/w3c/util/ThreadCache.java, revision 1.8

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

Webmaster