/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.mx.util;
import java.util.Stack;
/**
* A simple thread pool. Idle threads are cached for future use.
* The cache grows until it reaches a maximum size (default 10).
* When there is nothing in the cache, a new thread is created.
* By default the threads are daemon threads.
*
* Rickard \u00d6berg
* Adrian Brock
* @version $Revision: 57200 $
*/
public class ThreadPool
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
private static int counter = 0;
/**
* Stack of idle threads cached for future use.
*/
private Stack pool = new Stack();
/**
* Maximum number of idle threads cached in this pool.
*/
private int maxSize = 10;
/**
* Is the thread pool active
*/
private boolean active = false;
/**
* Whether the threads are daemon threads.
*/
private boolean daemon = true;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
/**
* Create a new pool.
*/
public ThreadPool()
{
}
/**
* Create a new pool with an activity status
*
* @param active true for active, false otherwise
*/
public ThreadPool(boolean active)
{
this.active = active;
}
// Public --------------------------------------------------------
/**
* Set the maximum number of idle threads cached in this pool.
*
* @param size the new maximum size.
*/
public void setMaximumSize(int size)
{
maxSize = size;
}
/**
* Get the maximum number of idle threads cached in this pool.
*
* @return the maximum size
*/
public int getMaximumSize()
{
return maxSize;
}
/**
* Set the activity status of the pool. Setting the pool to
* inactive, clears the pool.
*
* @param status pass true for active, false otherwise.
*/
public void setActive(boolean status)
{
active = status;
if (active == false)
while (pool.size() > 0)
((Worker)pool.pop()).die();
}
/**
* Get the activity status of the pool.
*
* @return true for an active pool, false otherwise.
*/
public boolean isActive()
{
return active;
}
/**
* Set whether new threads are daemon threads.
*
* @param value pass true for daemon threads, false otherwise.
*/
public void setDaemonThreads(boolean value)
{
daemon = value;
}
/**
* Get whether new threads are daemon threads.
*
* @return true for daemon threads, false otherwise.
*/
public boolean getDaemonThreads()
{
return daemon;
}
/**
* Do some work.
* This will either create a new thread to do the work, or
* use an existing idle cached thread.
*
* @param work the work to perform.
*/
public synchronized void run(Runnable work)
{
if (pool.size() == 0)
new Worker(work);
else
{
Worker worker = (Worker) pool.pop();
worker.run(work);
}
}
// Private -------------------------------------------------------
/**
* Put an idle worker thread back in the pool of cached idle threads.
* This is called from the worker thread itself. When the cache is
* full, the thread is discarded.
*
* @param worker the worker to return.
*/
private synchronized void returnWorker(Worker worker)
{
if (pool.size() < maxSize)
pool.push(worker);
else
worker.die();
}
// Inner classes -------------------------------------------------
/**
* A worker thread runs a worker.
*/
class Worker extends Thread
{
/**
* Flags that this worker may continue to work.
*/
boolean running = true;
/**
* Work to do, of null
if no work to do.
*/
Runnable work;
/**
* Create a new Worker to do some work.
*
* @param work the work to perform
*/
Worker(Runnable work)
{
// give it a thread so we can figure out what this thread is in debugging
super("ThreadPoolWorker["+(++counter)+"]");
this.work = work;
setDaemon(daemon);
start();
}
/**
* Tell this worker to die.
*/
public synchronized void die()
{
running = false;
this.notify();
}
/**
* Give this Worker some work to do.
*
* @param the work to perform.
* @throws IllegalStateException If this worker already
* has work to do.
*/
public synchronized void run(Runnable work)
{
if (this.work != null)
throw new IllegalStateException("Worker already has work to do.");
this.work = work;
this.notify();
}
/**
* The worker loop.
*/
public void run()
{
while (active && running)
{
// If work is available then execute it
if (work != null)
{
try
{
work.run();
}
catch (Exception ignored) {}
// Clear work
work = null;
}
// Return to pool of cached idle threads
returnWorker(this);
// Wait for more work to become available
synchronized (this)
{
while (running && work == null)
{
try
{
this.wait();
}
catch (InterruptedException ignored) {}
}
}
}
}
}
}