tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cos...@apache.org
Subject cvs commit: jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads ThreadPool.java
Date Thu, 19 Dec 2002 05:45:42 GMT
costin      2002/12/18 21:45:42

  Modified:    util/java/org/apache/tomcat/util/threads ThreadPool.java
  Log:
  - use commons-logging directly.
  - remove unused imports ( thanks idea )
  - added a ThreadListener. It'll be used to add
   JMX proxies for the thread pool ( and it can be used to
  get notifications of thread start and end ).
  - added missing getters
  - added a method to list the threads in the pool
  - (experimental) instead of creating Thread, the code
  will create ThreadWithAttributes. This would allow O(1)
  notes to be stored.
  
  I want to add JMX support and make calls to store the
  "state" of the thread, i.e. what is the thread doing.
  This would allow people to debug hunged threads and
  allow more control.
  
  Revision  Changes    Path
  1.5       +161 -33   jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java
  
  Index: ThreadPool.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ThreadPool.java	27 Nov 2002 20:12:17 -0000	1.4
  +++ ThreadPool.java	19 Dec 2002 05:45:42 -0000	1.5
  @@ -1,7 +1,4 @@
   /*
  - * $Header$
  - * $Revision$
  - * $Date$
    *
    * ====================================================================
    *
  @@ -63,11 +60,9 @@
   
   package org.apache.tomcat.util.threads;
   
  -import java.util.zip.*;
  -import java.net.*;
   import java.util.*;
  -import java.io.*;
  -import org.apache.tomcat.util.log.*; 
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
   
   /**
    * A thread pool that is trying to copy the apache process management.
  @@ -75,6 +70,7 @@
    * @author Gal Shachor
    */
   public class ThreadPool  {
  +    static Log log = LogFactory.getLog(ThreadPool.class);
   
       /*
        * Default values ...
  @@ -130,10 +126,17 @@
       
       static int debug=0;
   
  +    /** The threads that are part of the pool.
  +     * Key is Thread, value is the ControlRunnable
  +     */
  +    protected Hashtable threads=new Hashtable();
  +
  +    protected Vector listeners=new Vector();
  +
       /**
        * Helper object for logging
        **/
  -    Log loghelper = Log.getLog("tc/ThreadPool", "ThreadPool");
  +    //Log loghelper = Log.getLog("tc/ThreadPool", "ThreadPool");
       
       public ThreadPool() {
           maxThreads      = MAX_THREADS;
  @@ -157,6 +160,10 @@
           monitor = new MonitorRunnable(this);
       }
   
  +    public MonitorRunnable getMonitor() {
  +        return monitor;
  +    }
  +
       public void setMaxThreads(int maxThreads) {
           this.maxThreads = maxThreads;
       }
  @@ -181,6 +188,22 @@
           return maxSpareThreads;
       }
   
  +    public int getCurrentThreadCount() {
  +        return currentThreadCount;
  +    }
  +
  +    public int getCurrentThreadsBusy() {
  +        return currentThreadsBusy;
  +    }
  +
  +    public boolean isDaemon() {
  +        return isDaemon;
  +    }
  +
  +    public static int getDebug() {
  +        return debug;
  +    }
  +
       /** 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.
  @@ -192,7 +215,31 @@
       public boolean getDaemon() {
           return isDaemon;
       }
  -    
  +
  +    public void addThread( Thread t, 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 void removeThread( Thread t ) {
  +        threads.remove(t);
  +        for( int i=0; i<listeners.size(); i++ ) {
  +            ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
  +            tpl.threadEnd(this, t);
  +        }
  +    }
  +
  +    public void addThreadPoolListener( ThreadPoolListener tpl ) {
  +        listeners.addElement( tpl );
  +    }
  +
  +    public Enumeration getThreads(){
  +        return threads.keys();
  +    }
  +
       //
       // You may wonder what you see here ... basically I am trying
       // to maintain a stack of threads. This way locality in time
  @@ -225,7 +272,7 @@
                       int toOpen = currentThreadCount + minSpareThreads;
                       openThreads(toOpen);
                   } else {
  -		    logFull(loghelper, currentThreadCount, maxThreads);
  +		    logFull(log, currentThreadCount, maxThreads);
                       // Wait for a thread to become idel.
                       while(currentThreadsBusy == currentThreadCount) {
                           try {
  @@ -237,7 +284,7 @@
   			// it'll never actually happen, since nowhere
   			// do we say pool.interrupt().
   			catch(InterruptedException e) {
  -			    loghelper.log("Unexpected exception", e);
  +			    log.error("Unexpected exception", e);
                           }
   
                           // Pool was stopped. Get away of the pool.
  @@ -258,10 +305,10 @@
       static boolean logfull=true;
       public static void logFull(Log loghelper, int currentThreadCount, int maxThreads) {
   	if( logfull ) {
  -	    loghelper.log("All threads are busy, waiting. Please " +
  -			  "increase maxThreads or check the servlet" +
  -			  " status" + currentThreadCount + " " +
  -			  maxThreads  );
  +            log.error("All threads are busy, waiting. Please " +
  +                    "increase maxThreads or check the servlet" +
  +                    " status" + currentThreadCount + " " +
  +                    maxThreads  );
   	    logfull=false;
   	} 
       }
  @@ -282,7 +329,7 @@
   		     * Do nothing... The show must go on, we are shutting
   		     * down the pool and nothing should stop that.
   		     */
  -		    loghelper.log("Ignored exception while shutting down thread pool", t, Log.ERROR);
  +		    log.error("Ignored exception while shutting down thread pool", t);
                   }
               }
               currentThreadsBusy = currentThreadCount = 0;
  @@ -390,28 +437,38 @@
           currentThreadCount = toOpen;
       }
   
  +    /** @deprecated */
       void log( String s ) {
  -	loghelper.log(s);
  -	loghelper.flush();
  +	log.info(s);
  +	//loghelper.flush();
       }
       
       /** 
        * Periodically execute an action - cleanup in this case
        */
  -    class MonitorRunnable implements Runnable {
  +    public static class MonitorRunnable implements Runnable {
           ThreadPool p;
           Thread     t;
  +        int interval=WORK_WAIT_TIMEOUT;
           boolean    shouldTerminate;
   
           MonitorRunnable(ThreadPool p) {
  +            this.p=p;
  +            this.start();
  +        }
  +
  +        public void start() {
               shouldTerminate = false;
  -            this.p = p;
               t = new Thread(this);
               t.setDaemon(p.getDaemon() );
   	    t.setName( "MonitorRunnable" );
               t.start();
           }
   
  +        public void setInterval(int i ) {
  +            this.interval=i;
  +        }
  +
           public void run() {
               while(true) {
                   try {
  @@ -430,12 +487,15 @@
                       p.checkSpareControllers();
   
                   } catch(Throwable t) {
  -		    loghelper.log("Unexpected exception", t);
  -		    loghelper.flush();
  +		    ThreadPool.log.error("Unexpected exception", t);
                   }
               }
           }
   
  +        public void stop() {
  +            this.terminate();
  +        }
  +
   	/** Stop the monitor
   	 */
           public synchronized void terminate() {
  @@ -448,9 +508,8 @@
        * A Thread object that executes various actions ( ThreadPoolRunnable )
        *  under control of ThreadPool
        */
  -    class ControlRunnable implements Runnable {
  -
  -	/**
  +    public static class ControlRunnable implements Runnable {
  +        /**
   	 * ThreadPool where this thread will be returned
   	 */
           ThreadPool p;
  @@ -492,9 +551,10 @@
               shouldTerminate = false;
               shouldRun = false;
               this.p = p;
  -            t = new Thread(this);
  +            t = new ThreadWithAttributes(p, this);
               t.setDaemon(true);
               t.start();
  +            p.addThread( t, this );
   	    noThData=true;
   	    thData=null;
           }
  @@ -510,18 +570,21 @@
                           }
                       }
                       if(toRun == null ) {
  -                            if( p.debug>0) p.log( "No toRun ???");
  +                            if( p.log.isDebugEnabled())
  +                                p.log.debug( "No toRun ???");
                       }
   
                       if( shouldTerminate ) {
  -                            if( p.debug>0) p.log( "Terminate");
  +                            if( p.log.isDebugEnabled())
  +                                p.log.debug( "Terminate");
                               break;
                       }
   
                       /* Check if should execute a runnable.  */
                       try {
                           if(noThData) {
  -                            if(p.debug>0) p.log( "Getting new thread data");
  +                            if(p.log.isDebugEnabled())
  +                                p.log.debug( "Getting new thread data");
                               thData=toRun.getInitData();
                               noThData = false;
                           }
  @@ -530,8 +593,7 @@
   			    toRun.runIt(thData);
                           }
                       } catch(Throwable t) {
  -			loghelper.log("Caught exception executing " + toRun.toString() + ", terminating thread",
t);
  -			loghelper.flush();
  +			p.log.error("Caught exception executing " + toRun.toString() + ", terminating thread",
t);
                           /*
                           * The runnable throw an exception (can be even a ThreadDeath),
                           * signalling that the thread die.
  @@ -561,12 +623,15 @@
                       }
                   } catch(InterruptedException ie) { /* for the wait operation */
   		    // can never happen, since we don't call interrupt
  -		    loghelper.log("Unexpected exception", ie);
  -		    loghelper.flush();
  +    		    p.log.error("Unexpected exception", ie);
                   }
               }
           }
   
  +        /** Run a task
  +         *
  +         * @param toRun
  +         */
           public synchronized void runIt(ThreadPoolRunnable toRun) {
   	    if( toRun == null ) {
   		throw new NullPointerException("No Runnable");
  @@ -580,9 +645,72 @@
               this.notify();
           }
   
  +        public void stop() {
  +            this.terminate();
  +        }
  +
  +        public void kill() {
  +            t.stop();
  +        }
  +
           public synchronized void terminate() {
               shouldTerminate = true;
               this.notify();
           }
  +    }
  +
  +    /** Special thread that allows storing of attributes and notes.
  +     *  A guard is used to prevent untrusted code from accessing the
  +     *  attributes.
  +     *
  +     *  This avoids hash lookups and provide something very similar
  +     * with ThreadLocal ( but compatible with JDK1.1 and faster on
  +     * JDK < 1.4 ).
  +     *
  +     * The main use is to store 'state' for monitoring ( like "processing
  +     * request 'GET /' ").
  +     */
  +    public static class ThreadWithAttributes extends Thread {
  +        private Object control;
  +        public static int MAX_NOTES=16;
  +        private Object notes[]=new Object[MAX_NOTES];
  +        private Hashtable attributes=new Hashtable();
  +        private String currentStage;
  +
  +        public ThreadWithAttributes(Object control, Runnable r) {
  +            super(r);
  +            this.control=control;
  +        }
  +
  +        public void setNote( Object control, int id, Object value ) {
  +            if( this.control != control ) return;
  +            notes[id]=value;
  +        }
  +
  +        public String getCurrentStage() {
  +            return currentStage;
  +        }
  +
  +        public void setCurrentStage(String currentStage) {
  +            this.currentStage = currentStage;
  +        }
  +
  +        public Object getNote(Object control, int id ) {
  +            if( this.control != control ) return null;
  +            return notes[id];
  +        }
  +
  +        public Hashtable getAttributes(Object control) {
  +            return attributes;
  +        }
  +    }
  +
  +    /** Interface to allow applications to be notified when
  +     * a threads are created and stopped.
  +     */
  +    public static interface ThreadPoolListener {
  +        public void threadStart( ThreadPool tp, Thread t);
  +
  +        public void threadEnd( ThreadPool tp, Thread t);
       }
   }
  
  
  

--
To unsubscribe, e-mail:   <mailto:tomcat-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:tomcat-dev-help@jakarta.apache.org>


Mime
View raw message