/* * Copyright 2003,2004 Colin Crist * * Licensed 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. * */ package hermes.browser.tasks; import hermes.SingletonManager; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.log4j.Logger; /** * Absolutely no JMS work can occur on the main, GUI thread. So all the work * gets delegated to this thread pool to do... * * @author colincrist@hermesjms.com * @version $Id: ThreadPool.java,v 1.8 2006/08/01 07:29:36 colincrist Exp $ */ public class ThreadPool implements Runnable { private static final Logger log = Logger.getLogger(ThreadPool.class); private static final ThreadPool threadPool = new ThreadPool(1); private ArrayList<Runnable> tasks = new ArrayList<Runnable>(); private List<Thread> threads = new ArrayList<Thread>(); private int nthreads; private Set<Runnable> running = new HashSet<Runnable>(); private List<ThreadPoolActiveListener> listeners = new ArrayList<ThreadPoolActiveListener>(); static { SingletonManager.put(ThreadPool.class, new ThreadPool(1)); } public static ThreadPool get() { return (ThreadPool) SingletonManager.get(ThreadPool.class); } public ThreadPool(int nthreads) { this.nthreads = nthreads; for (int i = 0; i < nthreads; i++) { Thread t = new Thread(this, "Hermes ThreadPool-" + i); threads.add(t); t.setDaemon(true); t.start(); } } public void setClassLoader(ClassLoader classLoader) { for (final Thread t : threads) { log.debug("updating ContextClassLoader on " + t.getName()); t.setContextClassLoader(classLoader); } } public void invokeLater(Runnable run) { synchronized (tasks) { tasks.add(run); tasks.notify(); } } public void addActiveListener(ThreadPoolActiveListener listener) { listeners.add(listener); } public void removeActiveListener(ThreadPoolActiveListener listener) { listeners.remove(listener); } public void stopAll() { synchronized (tasks) { synchronized (running) { for (final Runnable r : running) { if (r instanceof Task) { Task task = (Task) r; task.stop(); } } } tasks.clear(); } } public void run() { // // Minimum priority means the GUI will always get priority. Thread.currentThread().setPriority(Thread.MIN_PRIORITY) ; boolean keepRunning = true; while (keepRunning) { Runnable task = null; synchronized (tasks) { while (tasks.size() == 0) { try { for (final ThreadPoolActiveListener l : listeners) { l.onInactive(); } tasks.wait(); } catch (InterruptedException ex) { log.error(ex.getMessage(), ex); } } task = (Runnable) tasks.remove(0); } for (final ThreadPoolActiveListener l : listeners) { l.onActive(); } log.debug("task " + task + " starting"); try { synchronized (running) { running.add(task); } task.run(); } catch (Throwable ex) { log.error("during run(): " + ex.getMessage(), ex); } finally { synchronized (running) { running.remove(task); } } log.debug("task " + task + " stopped"); synchronized (threads) { if (threads.size() > nthreads) { threads.remove(Thread.currentThread()); keepRunning = false; log.debug("threadpool shrinking to " + threads.size()); } } } } public void setThreads(int n) { if (n > nthreads) { log.debug("growing threadpool to " + n); for (int i = nthreads; i < n; i++) { Thread t = new Thread(this, "Hermes ThreadPool-" + i); synchronized (threads) { threads.add(t); } t.setDaemon(true); t.start(); } } nthreads = n; } public int getSize() { return nthreads ; } }