FileDocCategorySizeDatePackage
ThreadPool.javaAPI DocGlassfish v2 API24690Fri May 04 22:33:18 BST 2007org.apache.tomcat.util.threads

ThreadPool

public class ThreadPool extends Object
A thread pool that is trying to copy the apache process management.
author
Gal Shachor

Fields Summary
private static com.sun.org.apache.commons.logging.Log
log
private static org.apache.tomcat.util.res.StringManager
sm
private static boolean
logfull
public static final int
MAX_THREADS
public static final int
MAX_THREADS_MIN
public static final int
MAX_SPARE_THREADS
public static final int
MIN_SPARE_THREADS
public static final int
WORK_WAIT_TIMEOUT
protected ControlRunnable[]
pool
protected MonitorRunnable
monitor
protected int
maxThreads
protected int
minSpareThreads
protected int
maxSpareThreads
protected int
currentThreadCount
protected int
currentThreadsBusy
protected boolean
stopThePool
protected boolean
isDaemon
protected Hashtable
threads
The threads that are part of the pool. Key is Thread, value is the ControlRunnable
protected Vector
listeners
protected String
name
Name of the threadpool
protected int
sequence
Sequence.
Constructors Summary
public ThreadPool()
Constructor.



              
      
        maxThreads = MAX_THREADS;
        maxSpareThreads = MAX_SPARE_THREADS;
        minSpareThreads = MIN_SPARE_THREADS;
        currentThreadCount = 0;
        currentThreadsBusy = 0;
        stopThePool = false;
    
Methods Summary
public voidaddThread(java.lang.Thread t, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable cr)

        threads.put( t, cr );
        for( int i=0; i<listeners.size(); i++ ) {
            ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
            tpl.threadStart(this, t);
        }
    
public voidaddThreadPoolListener(org.apache.tomcat.util.threads.ThreadPool$ThreadPoolListener tpl)

        listeners.addElement( tpl );
    
protected voidadjustLimits()

        if(maxThreads <= 0) {
            maxThreads = MAX_THREADS;
        } else if (maxThreads < MAX_THREADS_MIN) {
            log.warn(sm.getString("threadpool.max_threads_too_low",
                                  Integer.valueOf(maxThreads),
                                  Integer.valueOf(MAX_THREADS_MIN)));
            maxThreads = MAX_THREADS_MIN;
        }

        if(maxSpareThreads >= maxThreads) {
            maxSpareThreads = maxThreads;
        }

        if(maxSpareThreads <= 0) {
            if(1 == maxThreads) {
                maxSpareThreads = 1;
            } else {
                maxSpareThreads = maxThreads/2;
            }
        }

        if(minSpareThreads >  maxSpareThreads) {
            minSpareThreads =  maxSpareThreads;
        }

        if(minSpareThreads <= 0) {
            if(1 == maxSpareThreads) {
                minSpareThreads = 1;
            } else {
                minSpareThreads = maxSpareThreads/2;
            }
        }
    
protected synchronized voidcheckSpareControllers()
Called by the monitor thread to harvest idle threads.


        if(stopThePool) {
            return;
        }

        if((currentThreadCount - currentThreadsBusy) > maxSpareThreads) {
            int toFree = currentThreadCount -
                         currentThreadsBusy -
                         maxSpareThreads;

            for(int i = 0 ; i < toFree ; i++) {
                ControlRunnable c = pool[currentThreadCount - currentThreadsBusy - 1];
                c.terminate();
                pool[currentThreadCount - currentThreadsBusy - 1] = null;
                currentThreadCount --;
            }

        }

    
public static org.apache.tomcat.util.threads.ThreadPoolcreateThreadPool(boolean jmx)
Create a ThreadPool instance.

param
jmx True if you want a pool with JMX support. A regular pool will be returned if JMX or the modeler are not available.
return
ThreadPool instance. If JMX support is requested, you need to call register() in order to set a name.

//        if( jmx ) {
//            try {
//                Class.forName( "com.sun.org.apache.commons.modeler.Registry");
//                Class tpc=Class.forName( "org.apache.tomcat.util.threads.ThreadPoolMX");
//                ThreadPool res=(ThreadPool)tpc.newInstance();
//                return res;
//            } catch( Exception ex ) {
//            }
//        }
        return new ThreadPool();
    
private org.apache.tomcat.util.threads.ThreadPool$ControlRunnablefindControlRunnable()

        ControlRunnable c=null;

        if ( stopThePool ) {
            throw new IllegalStateException();
        }

        // Obtain a free thread from the pool.
        synchronized(this) {

            while (currentThreadsBusy == currentThreadCount) {
                 // All threads are busy
                if (currentThreadCount < maxThreads) {
                    // Not all threads were open,
                    // Open new threads up to the max number of idel threads
                    int toOpen = currentThreadCount + minSpareThreads;
                    openThreads(toOpen);
                } else {
                    logFull(log, currentThreadCount, maxThreads);
                    // Wait for a thread to become idel.
                    try {
                        this.wait();
                    }
                    // was just catch Throwable -- but no other
                    // exceptions can be thrown by wait, right?
                    // So we catch and ignore this one, since
                    // it'll never actually happen, since nowhere
                    // do we say pool.interrupt().
                    catch(InterruptedException e) {
                        log.error("Unexpected exception", e);
                    }
		    if( log.isDebugEnabled() ) {
			log.debug("Finished waiting: CTC="+currentThreadCount +
				  ", CTB=" + currentThreadsBusy);
                    }
                    // Pool was stopped. Get away of the pool.
                    if( stopThePool) {
                        break;
                    }
                }
            }
            // Pool was stopped. Get away of the pool.
            if(0 == currentThreadCount || stopThePool) {
                throw new IllegalStateException();
            }
                    
            // If we are here it means that there is a free thread. Take it.
            int pos = currentThreadCount - currentThreadsBusy - 1;
            c = pool[pos];
            pool[pos] = null;
            currentThreadsBusy++;

        }
        return c;
    
public intgetCurrentThreadCount()

        return currentThreadCount;
    
public intgetCurrentThreadsBusy()

        return currentThreadsBusy;
    
public booleangetDaemon()

        return isDaemon;
    
public static intgetDebug()

        return 0;
    
public intgetMaxSpareThreads()

        return maxSpareThreads;
    
public intgetMaxThreads()

        return maxThreads;
    
public intgetMinSpareThreads()

        return minSpareThreads;
    
public org.apache.tomcat.util.threads.ThreadPool$MonitorRunnablegetMonitor()

        return monitor;
    
public java.lang.StringgetName()

        return name;
    
public intgetSequence()

        return sequence++;
    
public java.lang.String[]getThreadParam()
Return an array with the current "param" ( XXX better name ? ) of each thread. This is typically the last request.

return

        String status[]=new String[ threads.size()];
        Iterator it=threads.keySet().iterator();
        for( int i=0; ( i<status.length && it.hasNext()); i++ ) {
            ThreadWithAttributes twa=(ThreadWithAttributes)
                    it.next();
            Object o=twa.getParam(this);
            status[i]=(o==null)? null : o.toString();
        }
        return status;
    
public java.lang.String[]getThreadStatus()
Return an array with the status of each thread. The status indicates the current request processing stage ( for tomcat ) or whatever the thread is doing ( if the application using TP provide this info )

return

        String status[]=new String[ threads.size()];
        Iterator it=threads.keySet().iterator();
        for( int i=0; ( i<status.length && it.hasNext()); i++ ) {
            ThreadWithAttributes twa=(ThreadWithAttributes)
                    it.next();
            status[i]=twa.getCurrentStage(this);
        }
        return status;
    
public java.util.EnumerationgetThreads()

        return threads.keys();
    
public booleanisDaemon()

        return isDaemon;
    
voidlog(java.lang.String s)

deprecated

	log.info(s);
	//loghelper.flush();
    
private static voidlogFull(com.sun.org.apache.commons.logging.Log loghelper, int currentThreadCount, int maxThreads)

	if( logfull ) {
            log.error(sm.getString("threadpool.busy",
                                   Integer.valueOf(currentThreadCount),
                                   Integer.valueOf(maxThreads)));
            logfull=false;
        } else if( log.isDebugEnabled() ) {
            log.debug("All threads are busy " + currentThreadCount + " " +
                      maxThreads );
        }
    
protected synchronized voidnotifyThreadEnd(org.apache.tomcat.util.threads.ThreadPool$ControlRunnable c)
Inform the pool that the specific thread finish. Called by the ControlRunnable.run() when the runnable throws an exception.

        currentThreadsBusy--;
        currentThreadCount --;
        notify();
    
protected voidopenThreads(int toOpen)
Create missing threads.

param
toOpen Total number of threads we'll have open


        if(toOpen > maxThreads) {
            toOpen = maxThreads;
        }

        for(int i = currentThreadCount ; i < toOpen ; i++) {
            pool[i - currentThreadsBusy] = new ControlRunnable(this);
        }

        currentThreadCount = toOpen;
    
public voidremoveThread(java.lang.Thread t)

        threads.remove(t);
        for( int i=0; i<listeners.size(); i++ ) {
            ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
            tpl.threadEnd(this, t);
        }
    
protected synchronized voidreturnController(org.apache.tomcat.util.threads.ThreadPool$ControlRunnable c)
Returns the thread to the pool. Called by threads as they are becoming idel.


        if(0 == currentThreadCount || stopThePool) {
            c.terminate();
            return;
        }

        // atomic
        currentThreadsBusy--;

        pool[currentThreadCount - currentThreadsBusy - 1] = c;
        notify();
    
public voidrun(java.lang.Runnable r)

        ControlRunnable c = findControlRunnable();
        c.runIt(r);
    
public voidrunIt(ThreadPoolRunnable r)
Executes a given Runnable on a thread in the pool, block if needed.

        if(null == r) {
            throw new NullPointerException();
        }

        ControlRunnable c = findControlRunnable();
        c.runIt(r);
    
public voidsetDaemon(boolean b)
The default is true - the created threads will be in daemon mode. If set to false, the control thread will not be daemon - and will keep the process alive.

        isDaemon=b;
    
public voidsetMaxSpareThreads(int maxSpareThreads)

        this.maxSpareThreads = maxSpareThreads;
    
public voidsetMaxThreads(int maxThreads)

        this.maxThreads = maxThreads;
    
public voidsetMinSpareThreads(int minSpareThreads)

        this.minSpareThreads = minSpareThreads;
    
public voidsetName(java.lang.String name)

        this.name = name;
    
public synchronized voidshutdown()
Stop the thread pool

        if(!stopThePool) {
            stopThePool = true;
            monitor.terminate();
            monitor = null;
            for(int i = 0 ; i < currentThreadCount - currentThreadsBusy; i++) {
                try {
                    pool[i].terminate();
                } catch(Throwable t) {
                    /*
		     * Do nothing... The show must go on, we are shutting
		     * down the pool and nothing should stop that.
		     */
		    log.error("Ignored exception while shutting down thread pool", t);
                }
            }
            currentThreadsBusy = currentThreadCount = 0;
            pool = null;
            notifyAll();
        }
    
public synchronized voidstart()

	stopThePool=false;
        currentThreadCount  = 0;
        currentThreadsBusy  = 0;

        adjustLimits();

        pool = new ControlRunnable[maxThreads];

        openThreads(minSpareThreads);
        monitor = new MonitorRunnable(this);
        if (maxSpareThreads < maxThreads) {
            monitor = new MonitorRunnable(this);
        }
    
public java.lang.StringthreadStatusString()
Debug display of the stage of each thread. The return is html style, for display in the console ( it can be easily parsed too )

return

        StringBuffer sb=new StringBuffer();
        Iterator it=threads.keySet().iterator();
        sb.append("<ul>");
        while( it.hasNext()) {
            sb.append("<li>");
            ThreadWithAttributes twa=(ThreadWithAttributes)
                    it.next();
            sb.append(twa.getCurrentStage(this) ).append(" ");
            sb.append( twa.getParam(this));
            sb.append( "</li>\n");
        }
        sb.append("</ul>");
        return sb.toString();