8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
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 *
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 * opensso/legal/CDDLv1.0.txt
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * See the License for the specific language governing
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * permission and limitations under the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * When distributing Covered Code, include this CDDL
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Header Notice in each file and include the License file
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * at opensso/legal/CDDLv1.0.txt.
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 *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * $Id: ThreadPool.java,v 1.3 2008/06/25 05:41:41 qcheng Exp $
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterpackage com.iplanet.services.util;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// TODO:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// Stopping individual tasks
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// ThreadGroups
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster// Exception propagation or callbacks
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterimport com.sun.identity.shared.debug.Debug;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * <p>
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 * </p>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * <p>
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 * tasks.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * </p>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * <p>
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 * </p>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterpublic final class ThreadPool {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private static int nextThreadID = 1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private Debug debug;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private String poolName;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private IPSThread[] allThreadList;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private IPSThread[] idleThreadList;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private volatile int tail = -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * <p>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Constructs a thread pool with the poolName and given number of threads.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * </p>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
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 *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * @throws IllegalArgumentException
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * if poolName is null
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public ThreadPool(String poolName, int numThreads, boolean daemon,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Debug debug) throws IllegalArgumentException {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (poolName != null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.poolName = poolName;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } else {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster throw new IllegalArgumentException(
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster "Must assign a non-null pool name to ThreadPool");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.debug = debug;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // ensure that there is at least one thread in the pool
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster numThreads = Math.max(1, numThreads);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
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 // optmize.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster idleThreadList = new IPSThread[numThreads];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster allThreadList = new IPSThread[numThreads];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
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
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (int i = 0; i < numThreads; ++i) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster allThreadList[i] = new IPSThread(getNextIPSThreadID(), daemon);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Suppress the no-arg constructor because it is not supported */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private ThreadPool() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
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 }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 *
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public final void run(Runnable task) throws InterruptedException {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster IPSThread ipsThread;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (tail == -1) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((debug != null) && (debug.warningEnabled())) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.warning(Thread.currentThread().getName()
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + " waiting for an idle thread in " + toString());
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster idleThreadList.wait();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Now there is at least one idle thread available
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ipsThread = idleThreadList[tail--];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
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 }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // logMessage(Thread.currentThread().getName() + " assigning task '" +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // task + "' to " + ipsThread.getName());
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ipsThread.process(task);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public final void stopIdleThreads() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (tail >= 0) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster IPSThread idleThread = idleThreadList[tail];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster idleThreadList[tail--] = null;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster idleThread.stop();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public final void destroy() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // stop the idle threads first to be more productive
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster stopIdleThreads();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster try {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // give the idle threads a chance to die
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Thread.sleep(500);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } catch (InterruptedException e) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // no need to reassert InterruptedException here because the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // pool is being shutdown
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // now go through allThreadList and stop everything
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (allThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int numThreads = allThreadList.length;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int i = 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (i < numThreads) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster IPSThread ipsThread = allThreadList[i];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster allThreadList[i++] = null;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (ipsThread.isAlive()) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ipsThread.stop();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public String toString() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return poolName + "[" + allThreadList.length + " Total threads, "
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + ((tail >= 0) ? (tail + 1) : 0) + " Idle threads]";
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Returns the name of this thread pool */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public final String getName() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return poolName;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private final void logMessage(String msg) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (debug == null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.message(msg);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** ******************************************************************** */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** An inner class that actually executes the user-defined tasks. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private final class IPSThread {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // This internal thread will handle only one task at a time
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private volatile Runnable task;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private Thread thread;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private volatile boolean stopped = false;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster IPSThread(String name, boolean daemon) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Runnable r = new Runnable() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster public void run() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster try {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster runTask();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } catch (Throwable t) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // In case any exception slips through
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (debug != null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.error(IPSThread.this.thread.getName()
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + " caught exception that fell through", t);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster };
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster thread = new Thread(r, name);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster thread.setDaemon(daemon);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster thread.start();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Explicitly suppressed because it is not supported */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private IPSThread() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster final synchronized void process(Runnable task)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster throws InterruptedException {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.task = task;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Since only one thread can wait on this object, notifyAll() is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // not used.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster notify();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
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 */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private void runTask() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (!stopped) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster try {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // This thread is ready to rock-n-roll! Add this thread to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // the idleThreadList
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (idleThreadList) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster idleThreadList[++tail] = this;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // If idleThreadList was empty, notify the waiting
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // threads
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (tail == 0) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster idleThreadList.notifyAll();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Now wait until the parent pool assigns this thread a task
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster synchronized (this) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster while (task == null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster wait();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // logMessage(thread.getName() + " is running the task '" +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // task + "'");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster try {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster task.run();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } catch (Exception e) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (debug != null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.error(thread.getName()+
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster " caught exception that fell through from "
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster + task + ".run()", e);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } finally {
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
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Thread.interrupted();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } catch (InterruptedException e) {
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
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Thread.currentThread().interrupt(); // re-assert
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } catch (Throwable t) {
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 if (debug != null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.error(thread.getName()+
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ": runTask() caught throwable. Investigate " +
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster "the problem", t);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster } finally {
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 task = null;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (debug != null) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster debug.error(thread.getName() + " stopped.", (Throwable) null);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Stops this thread. This method may return before this thread actually
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * dies.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster private final void stop() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster logMessage(thread.getName() + " received stop() request.");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster stopped = true;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster thread.interrupt();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Gets the name of this thread */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster final String getName() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return thread.getName();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /** Checks if this thread is alive or dead */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster final boolean isAlive() {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return thread.isAlive();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}