Package net.sourceforge.cruisecontrol.util.threadpool

Source Code of net.sourceforge.cruisecontrol.util.threadpool.ThreadQueue

/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2001, ThoughtWorks, Inc.
* 651 W Washington Ave. Suite 600
* Chicago, IL 60661 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*     + Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*
*     + 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.
*
*     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 REGENTS OR
* 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.
********************************************************************************/

package net.sourceforge.cruisecontrol.util.threadpool;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import net.sourceforge.cruisecontrol.util.TdTimer;

import org.apache.log4j.Logger;

/**
* Used to encapsulate the concept of a Thread Pool
* <P>
* The queue accepts tasks that implement the WorkerThread interface.
* Each task may be named, but do not have to be.  You may then waitOn
* for ever task to complete or just the named tasks you care about...
* or not wait at all.
*
* @author Jared Richardson
* @version $Id: ThreadQueue.java,v 1.3 2004/09/07 21:34:03 jfredrick Exp $
*/

public class ThreadQueue extends Thread {
    private static final Logger LOG = Logger.getLogger(ThreadQueue.class);

    /**
     * The list of WorkerThreads that are waiting to run (currently idle)
     */
    private List idleTasks = Collections.synchronizedList(new LinkedList());
    /**
     * The list of WorkerThreads that are running now (currently busy)
     */
    private List busyTasks = Collections.synchronizedList(new LinkedList());

    /**
     * the resultList from each WorkerThread's run
     */
    private Map resultList = Collections.synchronizedMap(new HashMap());

    /**
     * Retains a handle to all the running Threads
     * to handle all sorts of interesting situations
     */

    private Map runningThreads = Collections.synchronizedMap(new HashMap());

    /**
     * The number of java.lang.Threads to be launched by the pool at one time
     */
    private int threadCount = ThreadQueueProperties.getMaxThreadCount();

    /**
     * The amount to time to sleep between loops
     */
    private static int sleepTime = 100;

    /**
     * A handle to the Thread Pool
     */
    private static ThreadQueue threadPool;

    /**
     * this variable is used to generate a unique name
     * for tasks that are not named when they arrive in
     * the queue
     */

    private static long nameCounter = Long.MIN_VALUE;

    /**
     * this variable is simple used to synchronize
     * access to the nameCounter above
     */

    private static Long nameCounterSynchObject = new Long("0");

    /**
     * tells the main process when to exit
     */
    private static boolean terminate = false;

    /*
       fetch tasks to be executed from the idle list,
       put them on the busy list, and
       execute them
    */
    public void run() {
        while (true) {
            if (ThreadQueue.terminate) {
                LOG.info("terminating ThreadQueue.run()");
                return;
            }

            final boolean nothingWaiting = idleTasks.size() == 0;
            final boolean maxedOut = busyTasks.size() >= threadCount;

            if (nothingWaiting || maxedOut) {
                sleep(sleepTime);
            } else {
                LOG.debug("handling waiting task");
                handleWaitingTask();
            }

            cleanCompletedTasks();
        }
    }

    private void handleWaitingTask() {
        synchronized (busyTasks) {
            WorkerThread worker = (WorkerThread) idleTasks.remove(0);
            Thread thisThread = new Thread(worker);
            busyTasks.add(worker);
            runningThreads.put(worker, thisThread);
            if (!ThreadQueue.terminate) {
                thisThread.start();
            }
        }
    }

    private void cleanCompletedTasks() {
        synchronized (busyTasks) {
            Iterator tasks = busyTasks.iterator();
            while (tasks.hasNext()) {
                WorkerThread task = (WorkerThread) tasks.next();
                Object result = task.getResult();
                final boolean taskDone = result != null;
                if (taskDone) {
                    LOG.debug("Found a finished task");
                    LOG.debug("tempTask.getName() = " + task.getName());
                    LOG.debug("tempTask.getResult() = " + task.getResult());

                    resultList.put(task.getName(), result);
                    tasks.remove();
                    runningThreads.remove(task);
                }
            }
        }
    }

    /**
     * An internal wrapper around the creation of the
     * Thread Pool singleton
     */

    private static ThreadQueue getThreadQueue() {
        if (threadPool == null) {
            threadPool = new ThreadQueue();
            threadPool.start();
        }
        return threadPool;
    }

    /**
     * Adds a task to the idleList to be executed
     */
    public static void addTask(WorkerThread task) {
        LOG.debug("Preparing to add worker task " + task.getName());
        if (task.getName() == WorkerThread.BLANK_NAME) {
            task.setName(nextName());
        }
        //System.out.println("adding worker task "+task.getName());
        if (isActive(task.getName())) {
            throw new RuntimeException("Duplicate task name!");
        }
        synchronized (getThreadQueue().busyTasks) {
            getThreadQueue().idleTasks.add(task);
        }
    }

    /**
     * Checks to see if all tasks are done
     */
    public static boolean isQueueIdle() {
        synchronized (getThreadQueue().busyTasks) {
            return ((getThreadQueue().busyTasks.size() == 0) && (getThreadQueue().idleTasks.size() == 0));
        }
    }

    /**
     * Checks to see if a specific task is done
     */
    public static boolean isDone(String taskName) {
        return getThreadQueue().resultList.containsKey(taskName);
    }

    /**
     * Waits until all tasks are done
     * same as Thread t.wait()
     */
    public static void waitForAll() {
        while (!ThreadQueue.isQueueIdle()) {
            sleep(sleepTime);
        }
    }

    /**
     * Waits until all tasks are done
     * same as Thread t.wait()
     *
     * @return TRUE is all tasks finished, FALSE if timeout occurred
     */
    public static boolean waitForAll(int timeout) {
        TdTimer myTimer = new TdTimer();
        while (!ThreadQueue.isQueueIdle()) {
            sleep(sleepTime);
            if (myTimer.time() > timeout) {
                return false;
            }
        }
        return true;
    }

    /**
     * Waits for a specific task to finish
     * same as Thread t.wait()
     */
    public static void waitFor(String taskName) {
        if (!taskExists(taskName)) {
            LOG.debug("taskName " + taskName + " doesn't exist");
            return;
        }
        while (!getThreadQueue().resultList.containsKey(taskName)) {
            sleep(sleepTime);
        }
    }

    /**
     * Waits for a specific task to finish, but with a timeout
     * same as Thread t.wait(), but with a timeout
     *
     * @return TRUE if task finished, FALSE if timeout occurred
     */
    public static boolean waitFor(String taskName, int timeout) {
        if (!taskExists(taskName)) {
            return false;
        }
        TdTimer myTimer = new TdTimer();
        while (!getThreadQueue().resultList.containsKey(taskName)) {
            sleep(sleepTime);
            if (myTimer.split() > timeout) {
                return false;
            }
        }
        return true;
    }

    /**
     * Checks to see if a specific task is in our system
     *
     * @return TRUE if task is found, FALSE if not
     */
    public static boolean taskExists(String taskName) {
        synchronized (getThreadQueue().busyTasks) {
            // it's either done, busy or idle
            if ((getResult(taskName) == null)
                    && (getBusyTask(taskName) == null)
                    && (getIdleTask(taskName) == null)) {
                return false;
            }
            return true;
        }
    }

    /**
     * Checks to see if a specific task is either running or waiting in our system
     *
     * @return TRUE if task is waiting or running, FALSE if it is finished
     */
    public static boolean isActive(String taskName) {
        synchronized (getThreadQueue().busyTasks) {
            // it's either busy or idle
            if ((getBusyTask(taskName) == null)
                    && (getIdleTask(taskName) == null)) {
                return false;
            }
            return true;
        }
    }

    /**
     * fetch a result from a completed WorkerThread
     * a null result means it's not done yet
     */

    public static Object getResult(String workerName) {
        return getThreadQueue().resultList.get(workerName);
    }

    /**
     * tells you how many tasks are running now
     */
    public static int numRunningTasks() {
        return getThreadQueue().busyTasks.size();
    }

    /**
     * tells you how many tasks are waiting now
     */
    public static int numWaitingTasks() {
        return getThreadQueue().idleTasks.size();
    }

    /**
     * tells you how many tasks have completed
     */
    public static int numCompletedTasks() {
        return getThreadQueue().resultList.size();
    }

    /**
     * tells you if a task is waiting now
     */
    public static boolean isIdle(String taskName) {
        return getThreadQueue().idleTasks.contains(taskName);
    }

    /**
     * retrieves an active task from the busy list
     *
     * @return the active task (if present) or null if it cannot be found
     */
    private static WorkerThread getBusyTask(String taskName) {
        return getTask(taskName, getThreadQueue().busyTasks.iterator());
    }

    /**
     * retrieves an idle task from the idle list
     *
     * @return the idle task (if present) or null if it cannot be found
     */
    private static WorkerThread getIdleTask(String taskName) {
        return getTask(taskName, getThreadQueue().idleTasks.iterator());
    }

    /**
     * retrieves a task from the list
     *
     * @return the task (if present) or null if it cannot be found
     */
    private static WorkerThread getTask(String taskName, Iterator myIt) {
        while (myIt.hasNext()) {
            WorkerThread thisWorker = (WorkerThread) myIt.next();
            String tempString = thisWorker.getName();
            if (tempString.equalsIgnoreCase(taskName)) {
                return thisWorker;
            }
        }
        return null;
    }

    /**
     * returns a string telling you number of idle
     * and busy worker threads
     */
    public static String stats() {
        String stats = numRunningTasks() + " tasks running \n";
        stats += numWaitingTasks() + " tasks waiting \n";

        return stats;
    }

    /**
     * returns the number of idle, busy and finished
     * worker threads
     */
    public static int numTotalTasks() {
        int num = numRunningTasks() + numWaitingTasks() + numCompletedTasks();
        return num;
    }

    /**
     * Terminate the queue's operation
     */
    public static void terminate() {
        ThreadQueue.terminate = true;
        // give everyone up to 10 seconds to acknowledge the terminate
        ThreadQueue.waitForAll(10000);
        // empty the various
        getThreadQueue().idleTasks.clear();
        getThreadQueue().busyTasks.clear();
        getThreadQueue().resultList.clear();
        threadPool = null;
        getThreadQueue();
        ThreadQueue.terminate = false;
    }

    public static void interruptAllRunningTasks() {
        synchronized (getThreadQueue().busyTasks) {
            Map currentRunningThreads = getThreadQueue().runningThreads;
           
            terminateRunningTasks(currentRunningThreads);
            interruptRunningThreads(currentRunningThreads);
        }
    }

    private static void interruptRunningThreads(Map currentRunningThreads) {
        for (Iterator iter = currentRunningThreads.values().iterator(); iter.hasNext();) {
            Thread currentThread = (Thread) iter.next();
            currentThread.interrupt();
        }
    }

    private static void terminateRunningTasks(Map currentRunningThreads) {
        for (Iterator iter = currentRunningThreads.keySet().iterator(); iter.hasNext();) {
            WorkerThread currentTask = (WorkerThread) iter.next();
            currentTask.terminate();
           
            LOG.info("Preparing to stop " + currentTask.getName());
        }
    }

    /**
     * Waits for a specific task to finish
     * same as Thread t.wait()
     */
    public static void interrupt(String taskName) {
        synchronized (getThreadQueue().busyTasks) {

            // check for the taskName in the resultsList
            // if it's there, it's already finished
            // *return
            if (getResult(taskName) != null) {
                return;
            }

            // check for it in the idleList
            // *remove it (before it starts running)
            // *return

            if (ThreadQueue.isIdle(taskName)) {
                getThreadQueue().idleTasks.remove(taskName);
                return;
            } // end of if ( getThreadQueue().isIdle(taksName()) {

            // At this point, it must be busy if it is in our system
            // *interrupt it
            // *cleanup
            // *return
            WorkerThread thisWorker = getBusyTask(taskName);
            if (thisWorker != null) {
                Thread thisThread =
                        (Thread) getThreadQueue().runningThreads.get(thisWorker);
                thisThread.interrupt();
                getThreadQueue().busyTasks.remove(thisWorker);
                getThreadQueue().runningThreads.remove(thisThread);
            }
        }
    }

    /**
     * This call wraps the next unique name for a task
     * that is inerted with no name
     */

    private static String nextName() {
        synchronized (nameCounterSynchObject) {
            if (nameCounter == Long.MAX_VALUE) {
                nameCounter = Long.MIN_VALUE;
            }
        }
        nameCounter++;
        return nameCounter + "";
    }

    /**
     * Tells the caller how many worker threads are in
     * use to service the worker tasks
     */

    static int getMaxNumWorkerThreads() {
        return getThreadQueue().threadCount;
    }

    /**
     * Utility call for sleeps
     */
    private static void sleep(int ms) {
        try {
            Thread.sleep(ms);
        } catch (Exception e) {
        }
    }
}
TOP

Related Classes of net.sourceforge.cruisecontrol.util.threadpool.ThreadQueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.