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

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

Webmaster