All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avaje.ebeaninternal.server.lib.thread.ThreadPool Maven / Gradle / Ivy

The newest version!
/**
 *  Copyright (C) 2006  Robin Bygrave
 *  
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
package com.avaje.ebeaninternal.server.lib.thread;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is a pool of threads which can be assigned work.
 * 

* The Pool will automatically grow as required up to its maximum pool size. The * Pool will be automatically shrink by trimming threads that have been idle for * some time. *

*/ public class ThreadPool { private static final Logger logger = Logger.getLogger(ThreadPool.class.getName()); /** * The max idle time used to trim idle threads from the pool. */ private long maxIdleTime; /** * The name of the pool */ private String poolName; /** * The initial pool size. */ private int minSize; /** * Whether or not the threads are going to be Daemon threads. */ private boolean isDaemon; /** * Flag to indicate that the pool is being shutdown. */ private boolean isStopping = false; /** * The priority or the threads. Can be null, in which case the threads have * the default priority. */ private Integer threadPriority; /** * Incrementing int for thread name. NB: currentThreadCount will go up and * down as the pool grows and shrinks. */ private int uniqueThreadID; /** * List of PooledThread that are free for work. */ private Vector freeList = new Vector(); /** * List of PooledThread that are busy. */ private Vector busyList = new Vector(); /** * List holding queued work. */ private Vector workOverflowQueue = new Vector(); /** * The maximum number of threads to grow to. Hitting this limit will have * performance ramifications. */ private int maxSize = 100; /** * Flag that the pool should terminate all the threads and stop. */ private boolean stopThePool; /** * Create the ThreadPool. */ public ThreadPool(String poolName, boolean isDaemon, Integer threadPriority) { this.poolName = poolName; this.stopThePool = false; this.isDaemon = isDaemon; this.threadPriority = threadPriority; } /** * Return true if the pool is shutting down. */ public boolean isStopping() { return isStopping; } /** * Return the name of the thread pool. */ public String getName() { return poolName; } /** * Set the minimum size the pool should try to maintain. */ public void setMinSize(int minSize) { if (minSize > 0) { if (minSize > maxSize) { this.maxSize = minSize; } this.minSize = minSize; maintainPoolSize(); } } /** * Return the minimum size the pool should maintain. */ public int getMinSize() { return minSize; } /** * Set the maximum size the pool should grow to. */ public void setMaxSize(int maxSize) { if (maxSize > 0) { if (minSize > maxSize) { minSize = maxSize; } this.maxSize = maxSize; maintainPoolSize(); } } /** * Return the maximum size this pool can grow to. */ public int getMaxSize() { return maxSize; } /** * Return the total number of busy and free threads in the pool. */ public int size() { return busyList.size() + freeList.size(); } /** * Return the number of currently busy threads. */ public int getBusyCount() { return busyList.size(); } /** * Assign a task to the thread pool, specifing the options to wait or queue * the task if the pool is fully busy and can't grow. *

* When the pool is fully busy... *

*

* addToQueue=true -> work is added to queue, returns false
* addToQueue=false -> work is not done or queued, returns false
*

* * @param work the runnable work to do. * @param addToQueueIfFull If the pool is maxed out and this is true then it * queues the Runnable. */ public boolean assign(Runnable work, boolean addToQueueIfFull) { if (stopThePool) { throw new RuntimeException("Pool is stopping... no more work please."); } Work runWork = new Work(work); // get the next available thread in the pool (block) PooledThread thread = getNextAvailableThread(); if (thread != null) { // assign the work to that thread busyList.add(thread); thread.assignWork(runWork); return true; } else { if (addToQueueIfFull) { runWork.setEnterQueueTime(System.currentTimeMillis()); workOverflowQueue.add(runWork); } return false; } } /** * Remove the thread from the pool. The thread should be stopped before it * is removed. */ protected void removeThread(PooledThread thread) { synchronized (freeList) { busyList.remove(thread); freeList.remove(thread); freeList.notify(); // if (ThreadPoolManager.getDebugLevel()>0){ //Log.debug("PooledThread stopped [" + getName() + "]"); // } } } /** * fired when a Thread from the pool has finished, and can be put back into * the pool. */ protected void returnThread(PooledThread thread) { synchronized (freeList) { // deregister from the busyList busyList.remove(thread); if (!workOverflowQueue.isEmpty()) { // get the first bit of work off the queue Work queuedWork = (Work) workOverflowQueue.remove(0); // work out the queue time and counts etc queuedWork.setExitQueueTime(System.currentTimeMillis()); busyList.add(thread); thread.assignWork(queuedWork); } else { // put the thread back onto the available list freeList.add(thread); // tell shutdown() one has returned freeList.notify(); } } } /** * Get the next available thread. Block until thread is available. NB: The * dispatcher is blocked but work can still be assigned to the dispatcher in * a non-blocking way */ private PooledThread getNextAvailableThread() { synchronized (freeList) { if (!freeList.isEmpty()) { return (PooledThread) freeList.remove(0); } if (size() < maxSize) { return growPool(true); } return null; } } /** * Return an Iterator of PooledThread that are currently running. You should * only use this for display. Use the getPooledThread() or interrupt() * methods to interrupt a particular thread. * * @return an Iterator of busy PooledThread's. */ public Iterator getBusyThreads() { synchronized (freeList) { return busyList.iterator(); } } /** * Shutdown the threadpool stopping all the threads. This will * wait until any busy threads have finished their assigned work. */ protected void shutdown() { synchronized (freeList) { isStopping = true; int size = size(); if (size > 0){ String msg = null; msg = "ThreadPool [" + poolName + "] Shutting down; threadCount[" + size() + "] busyCount[" + getBusyCount() + "]"; logger.info(msg); } stopThePool = true; while (!freeList.isEmpty()) { PooledThread thread = (PooledThread) freeList.remove(0); thread.stop(); } try { while (getBusyCount() > 0) { // synchronized (freeList) { String msg = "ThreadPool [" + poolName + "] has [" + getBusyCount() + "] busy threads, waiting for those to finish."; logger.info(msg); Iterator busyThreads = getBusyThreads(); while (busyThreads.hasNext()) { PooledThread busyThread = (PooledThread) busyThreads.next(); String threadName = busyThread.getName(); Work work = busyThread.getWork(); String busymsg = "Busy thread [" + threadName + "] work[" + work + "]"; logger.info(busymsg); } // trace("wait for a busy thread to be put back into // freeList"); freeList.wait(); PooledThread thread = (PooledThread) freeList.remove(0); // trace("wait finished...now shut it down [" + // thread.getName() + "]"); if (thread != null) { thread.stop(); } } } catch (InterruptedException e) { logger.log(Level.SEVERE, null, e); } } } /** * Trim or grow the pool leaving at least min free. */ protected void maintainPoolSize() { synchronized (freeList) { if (isStopping) { // don't bother as the pool is shutting down return; } int numToStop = size() - minSize; if (numToStop > 0) { // should trim idle threads as we are over the minSize long usedAfter = System.currentTimeMillis() - maxIdleTime; ArrayList stopList = new ArrayList(); Iterator it = freeList.iterator(); while (it.hasNext() && numToStop > 0) { PooledThread thread = (PooledThread) it.next(); if (thread.getLastUsedTime() < usedAfter) { stopList.add(thread); numToStop--; } } Iterator stopIt = stopList.iterator(); while (stopIt.hasNext()) { PooledThread thread = (PooledThread) stopIt.next(); thread.stop(); } } int numToAdd = minSize - size(); if (numToAdd > 0) { // should add some more to the pool for (int i = 0; i < numToAdd; i++) { growPool(false); } } } } /** * Interrupt a named thread that is currently busy. *

* Returns the thread that was interrupted or null if the thread * was not found. If the thread was interrupted then it will * automatically be stopped and removed from the pool. *

*

* Note that it may take some time to actually interrupt the thread so * an immediate test to see if the thread stopped will probably be wrong. *


     * ThreadPool test = ThreadPoolManager.getThreadPool("test");
     * PooledThread pt = test.interrupt("test.1");
     * if (pt == null) {
     *      // the thread was not found, perhaps finished?
     * } else {
     *      // give interrupt a little time to execute
     *      Thread.sleep(1000);
     *      boolean hasStopped = pt.isStopped();
     *      //..
     * }
     * 
*

* @return the thread that was interrupted */ public PooledThread interrupt(String threadName) { PooledThread thread = getBusyThread(threadName); if (thread != null) { thread.interrupt(); return thread; } return null; } /** * Find a thread using its name from the busy list. Returns null if the * thread is not found in the busy list. */ public PooledThread getBusyThread(String threadName) { synchronized (freeList) { Iterator it = getBusyThreads(); while (it.hasNext()) { PooledThread pt = (PooledThread) it.next(); if (pt.getName().equals(threadName)) { return pt; } } return null; } } /** * Grow the pool with the option of either putting it on the available list, * or returning it. */ private PooledThread growPool(boolean andReturn) { synchronized (freeList) { String threadName = poolName + "." + uniqueThreadID++; PooledThread bgw = new PooledThread(this, threadName, isDaemon, threadPriority); bgw.start(); if (logger.isLoggable(Level.FINE)) { logger.fine("ThreadPool grow created [" + threadName + "] size[" + size() + "]"); } if (andReturn) { return bgw; } else { freeList.add(bgw); return null; } } } /** * Return the maximum amount of time in millis that Threads can be idle * before they are trimmed. */ public long getMaxIdleTime() { return maxIdleTime; } /** * Set the maxiumium amount of time in millis that Threads can be idle * before they are trimed. */ public void setMaxIdleTime(long maxIdleTime) { this.maxIdleTime = maxIdleTime; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy