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

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