ThreadPool.java Source code

Java tutorial

Introduction

Here is the source code for ThreadPool.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */

import java.util.ArrayList;
import java.util.List;

/** Simple thread pool. A task is executed by obtaining a thread from
 * the pool
 */
public class ThreadPool {
    /** The thread pool contains instances of {@link ThreadPool.Task}.
     */
    public interface Task {
        /** Performs the task.
         * @throws Throwable The task failed, and the worker thread won't be used again.
         */
        void run() throws Throwable;
    }

    /** A task, which may be interrupted, if the pool is shutting down. 
     */
    public interface InterruptableTask extends Task {
        /** Interrupts the task.
         * @throws Throwable Shutting down the task failed.
         */
        void shutdown() throws Throwable;
    }

    private class Poolable {
        private boolean shuttingDown;
        private Task task;
        private Thread thread;

        Poolable(ThreadGroup pGroup, int pNum) {
            thread = new Thread(pGroup, pGroup.getName() + "-" + pNum) {
                public void run() {
                    while (!isShuttingDown()) {
                        final Task t = getTask();
                        if (t == null) {
                            try {
                                synchronized (this) {
                                    if (!isShuttingDown() && getTask() == null) {
                                        wait();
                                    }
                                }
                            } catch (InterruptedException e) {
                                // Do nothing
                            }
                        } else {
                            try {
                                t.run();
                                resetTask();
                                repool(Poolable.this);
                            } catch (Throwable e) {
                                discard(Poolable.this);
                                resetTask();
                            }
                        }
                    }
                }
            };
            thread.start();
        }

        synchronized void shutdown() {
            shuttingDown = true;
            final Task t = getTask();
            if (t != null && t instanceof InterruptableTask) {
                try {
                    ((InterruptableTask) t).shutdown();
                } catch (Throwable th) {
                    // Ignore me
                }
            }
            task = null;
            synchronized (thread) {
                thread.notify();
            }
        }

        private synchronized boolean isShuttingDown() {
            return shuttingDown;
        }

        String getName() {
            return thread.getName();
        }

        private synchronized Task getTask() {
            return task;
        }

        private synchronized void resetTask() {
            task = null;
        }

        synchronized void start(Task pTask) {
            task = pTask;
            synchronized (thread) {
                thread.notify();
            }
        }
    }

    private final ThreadGroup threadGroup;
    private final int maxSize;
    private final List waitingThreads = new ArrayList();
    private final List runningThreads = new ArrayList();
    private final List waitingTasks = new ArrayList();
    private int num;

    /** Creates a new instance.
     * @param pMaxSize Maximum number of concurrent threads.
     * @param pName Thread group name.
     */
    public ThreadPool(int pMaxSize, String pName) {
        maxSize = pMaxSize;
        threadGroup = new ThreadGroup(pName);
    }

    synchronized void discard(Poolable pPoolable) {
        pPoolable.shutdown();
        runningThreads.remove(pPoolable);
        waitingThreads.remove(pPoolable);
    }

    synchronized void repool(Poolable pPoolable) {
        if (runningThreads.remove(pPoolable)) {
            if (maxSize != 0 && runningThreads.size() + waitingThreads.size() >= maxSize) {
                discard(pPoolable);
            } else {
                waitingThreads.add(pPoolable);
                if (waitingTasks.size() > 0) {
                    Task task = (Task) waitingTasks.remove(waitingTasks.size() - 1);
                    startTask(task);
                }
            }
        } else {
            discard(pPoolable);
        }
    }

    /** Starts a task immediately.
     * @param pTask The task being started.
     * @return True, if the task could be started immediately. False, if
     * the maxmimum number of concurrent tasks was exceeded. If so, you
     * might consider to use the {@link #addTask(ThreadPool.Task)} method instead.
     */
    public synchronized boolean startTask(Task pTask) {
        if (maxSize != 0 && runningThreads.size() >= maxSize) {
            return false;
        }
        Poolable poolable;
        if (waitingThreads.size() > 0) {
            poolable = (Poolable) waitingThreads.remove(waitingThreads.size() - 1);
        } else {
            poolable = new Poolable(threadGroup, num++);
        }
        runningThreads.add(poolable);
        poolable.start(pTask);
        return true;
    }

    /** Adds a task for immediate or deferred execution.
     * @param pTask The task being added.
     * @return True, if the task was started immediately. False, if
     * the task will be executed later.
     */
    public synchronized boolean addTask(Task pTask) {
        if (startTask(pTask)) {
            return true;
        }
        waitingTasks.add(pTask);
        return false;
    }

    /** Closes the pool.
     */
    public synchronized void shutdown() {
        while (!waitingThreads.isEmpty()) {
            Poolable poolable = (Poolable) waitingThreads.remove(waitingThreads.size() - 1);
            poolable.shutdown();
        }
        while (!runningThreads.isEmpty()) {
            Poolable poolable = (Poolable) runningThreads.remove(runningThreads.size() - 1);
            poolable.shutdown();
        }
    }

    /** Returns the maximum number of concurrent threads.
     * @return Maximum number of threads.
     */
    public int getMaxThreads() {
        return maxSize;
    }

    /** Returns the number of threads, which have actually been created,
       * as opposed to the number of currently running threads.
     */
    public synchronized int getNumThreads() {
        return num;
    }
}