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

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

Webmaster