📄 threadpool.java
字号:
/* * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */package org.apache.tomcat.util.threads;import java.util.*;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;/** * A thread pool that is trying to copy the apache process management. * * @author Gal Shachor */public class ThreadPool { static Log log = LogFactory.getLog(ThreadPool.class); /* * Default values ... */ public static final int MAX_THREADS = 200; public static final int MAX_SPARE_THREADS = 50; public static final int MIN_SPARE_THREADS = 4; public static final int WORK_WAIT_TIMEOUT = 60*1000; /* * Where the threads are held. */ protected ControlRunnable[] pool = null; /* * A monitor thread that monitors the pool for idel threads. */ protected MonitorRunnable monitor; /* * Max number of threads that you can open in the pool. */ protected int maxThreads; /* * Min number of idel threads that you can leave in the pool. */ protected int minSpareThreads; /* * Max number of idel threads that you can leave in the pool. */ protected int maxSpareThreads; /* * Number of threads in the pool. */ protected int currentThreadCount; /* * Number of busy threads in the pool. */ protected int currentThreadsBusy; /* * Flag that the pool should terminate all the threads and stop. */ protected boolean stopThePool; /* Flag to control if the main thread is 'daemon' */ protected boolean isDaemon=true; /** 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(); /** Name of the threadpool */ protected String name=null; /** * Helper object for logging **/ //Log loghelper = Log.getLog("tc/ThreadPool", "ThreadPool"); public ThreadPool() { maxThreads = MAX_THREADS; maxSpareThreads = MAX_SPARE_THREADS; minSpareThreads = MIN_SPARE_THREADS; currentThreadCount = 0; currentThreadsBusy = 0; stopThePool = false; } /** 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. */ public static ThreadPool createThreadPool(boolean jmx) { return new ThreadPool(); } public void register( String domain, String name ) { // nothing in the base class - it'll register in jmx mode // We could use the name to create a ThreadGroup and name threads } public synchronized void start() { stopThePool=false; currentThreadCount = 0; currentThreadsBusy = 0; adjustLimits(); pool = new ControlRunnable[maxThreads]; openThreads(minSpareThreads); monitor = new MonitorRunnable(this); } public MonitorRunnable getMonitor() { return monitor; } public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } public int getMaxThreads() { return maxThreads; } public void setMinSpareThreads(int minSpareThreads) { this.minSpareThreads = minSpareThreads; } public int getMinSpareThreads() { return minSpareThreads; } public void setMaxSpareThreads(int maxSpareThreads) { this.maxSpareThreads = maxSpareThreads; } public int getMaxSpareThreads() { return maxSpareThreads; } public int getCurrentThreadCount() { return currentThreadCount; } public int getCurrentThreadsBusy() { return currentThreadsBusy; } public boolean isDaemon() { return isDaemon; } public static int getDebug() { return 0; } /** 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. */ public void setDaemon( boolean b ) { isDaemon=b; } 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 // is kept and there is a better chance to find residues of the // thread in memory next time it runs. // /** * Executes a given Runnable on a thread in the pool, block if needed. */ public void runIt(ThreadPoolRunnable r) { if(null == r) { throw new NullPointerException(); } if(0 == currentThreadCount || stopThePool) { throw new IllegalStateException(); } ControlRunnable c = null; // Obtain a free thread from the pool. synchronized(this) { if(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. while(currentThreadsBusy == currentThreadCount) { 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); } // 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. c = pool[currentThreadCount - currentThreadsBusy - 1]; currentThreadsBusy++; } c.runIt(r); } static boolean logfull=true; public static void logFull(Log loghelper, int currentThreadCount, int maxThreads) { if( logfull ) { log.error("All threads are busy, waiting. Please " + "increase maxThreads or check the servlet" + " status" + currentThreadCount + " " + maxThreads ); logfull=false; } } /** * Stop the thread pool */ public synchronized void shutdown() { if(!stopThePool) { stopThePool = true; monitor.terminate(); monitor = null; for(int i = 0 ; i < (currentThreadCount - currentThreadsBusy - 1) ; i++) { try { pool[i].terminate(); } catch(Throwable t) { /* * Do nothing... The show must go on, we are shutting
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -