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

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

Webmaster