8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The contents of this file are subject to the terms
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * of the Common Development and Distribution License
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * (the License). You may not use this file except in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * compliance with the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * You can obtain a copy of the License at
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * https://opensso.dev.java.net/public/CDDLv1.0.html or
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * See the License for the specific language governing
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * permission and limitations under the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * When distributing Covered Code, include this CDDL
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Header Notice in each file and include the License file
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If applicable, add the following below the CDDL Header,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * with the fields enclosed by brackets [] replaced by
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * your own identifying information:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * "Portions Copyrighted [year] [name of copyright owner]"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * $Id: ThreadPool.java,v 1.3 2008/06/25 05:41:41 qcheng Exp $
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// Stopping individual tasks
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// ThreadGroups
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// Exception propagation or callbacks
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * ThreadPool is a generic thread pool that manages and recycles threads instead
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * of creating them everytime some task needs to be run on a different thread.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Thread pooling saves the virtual machine the work of creating brand new
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * threads for every short-lived task. In addition, it minimizes overhead
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * associated with getting a thread started and cleaning it up after it dies. By
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * creating a pool of threads, a single thread from the pool can be reused any
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * number of times for different tasks.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * This reduces response time because a thread is already constructed and
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * started and is simply waiting for its next task. This is particularly useful
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * when using many short-lived tasks. This may not be useful for long-lived
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * In future, this class may be enhanced to provide support growing the size of
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the pool at runtime to facilitate dynamic tuning.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * tail points to the last available idle thread in the idleThreadList. When
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the idleThreadList is empty, tail is set to -1. IMPORTANT: tail MUST
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * always be accessed by acquiring a lock on idleThreadList. Otherwise, the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * code will break.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Constructs a thread pool with the poolName and given number of threads.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @param poolName
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * name of the thread pool
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @param numThreads
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * maximum number of threads in the thread pool.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @param daemon
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * if true, all threads created will be daemon threads. If false,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * all threads created will be non-daemon threads.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @param debug
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Debug object to send debug messages to.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @throws IllegalArgumentException
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * if poolName is null
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public ThreadPool(String poolName, int numThreads, boolean daemon,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster "Must assign a non-null pool name to ThreadPool");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // ensure that there is at least one thread in the pool
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Normally Lists should be used. However, since this class is a
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // performance-critical low level code, arrays are used to fully
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Now initialized only allThreads list. idleThreads list will be
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // updated by the threads when they are idle and ready.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster allThreadList[i] = new IPSThread(getNextIPSThreadID(), daemon);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Suppress the no-arg constructor because it is not supported */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Gets the unique name for the internal thread in the pool */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private synchronized String getNextIPSThreadID() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return poolName + ".Thread#" + Integer.toString(nextThreadID++);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Runs the user-defined task. To enable better debugging or profiling
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * capabilities, the <code>task</code> <code>Runnable</code> should
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * implement <code>toString()</code> to intuitively identify the task.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @param task
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the user-defined Runnable to be scheduled for execution on
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * this thread pool
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @throws InterruptedException
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * when the thread invoking <code>run</code> is interrupted.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public final void run(Runnable task) throws InterruptedException {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((debug != null) && (debug.warningEnabled())) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + " waiting for an idle thread in " + toString());
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Now there is at least one idle thread available
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Now that the idle thread is off the idleThreadList, there is no
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // danger of some other task being simultaneously assigned to that
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // idle thread. Release the lock on idleThreadList now so that
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // other tasks can be processed concurrently.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // logMessage(Thread.currentThread().getName() + " assigning task '" +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // task + "' to " + ipsThread.getName());
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Stops all the idle threads in the pool. Note that these stopped threads
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * are no longer availble for future tasks because they are returned to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * underlying virtual machine. Also note that none of the active threads in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the pool are stopped.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Destroys the thread pool. This stops all the threads, active and idle, in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the pool and releases all resources.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // stop the idle threads first to be more productive
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // give the idle threads a chance to die
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // no need to reassert InterruptedException here because the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // pool is being shutdown
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // now go through allThreadList and stop everything
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (allThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Returns the string representation of this thread pool that includes the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * name, size and the number of currently idle threads
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return poolName + "[" + allThreadList.length + " Total threads, "
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + ((tail >= 0) ? (tail + 1) : 0) + " Idle threads]";
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Returns the name of this thread pool */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** ******************************************************************** */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** An inner class that actually executes the user-defined tasks. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // This internal thread will handle only one task at a time
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public void run() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // In case any exception slips through
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + " caught exception that fell through", t);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Explicitly suppressed because it is not supported */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Accepts the user-defined task for execution. Note that by design this
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * method is called only when this thread is idle.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Since only one thread can wait on this object, notifyAll() is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // not used.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Actually runs the user-defined task. This thread adds itself to the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * idleThreadList in the parent pool and waits to be assinged a task.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * When the task is assinged, it goes ahead and executes it. While
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * executing, this thread is not on the idleThreadList.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // This thread is ready to rock-n-roll! Add this thread to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // the idleThreadList
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // If idleThreadList was empty, notify the waiting
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Now wait until the parent pool assigns this thread a task
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (this) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // logMessage(thread.getName() + " is running the task '" +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // task + "'");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster " caught exception that fell through from "
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Clear the interrupted flag (in case it comes back
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // set) so that if the loops goes again, the task.wait()
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // does not mistakenly throw an InterruptedException.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // This catch must be here (in addition to the one inside
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // the corresponding try{}) so that a task is not run
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // mistakenly after this thread is interrupted.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Thread.currentThread().interrupt(); // re-assert
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Fatal exception occurred. But we don't want to stop this
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // thread as that might only deplete the thread pool.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ": runTask() caught throwable. Investigate " +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster "the problem", t);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // set task to null so that the task doesn't get executed
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // repeatedly.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // logMessage(thread.getName() +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // " compeleted the task '" + task + "'");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.error(thread.getName() + " stopped.", (Throwable) null);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Stops this thread. This method may return before this thread actually
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster logMessage(thread.getName() + " received stop() request.");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Gets the name of this thread */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Checks if this thread is alive or dead */