001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.util;
023:
024: import java.util.Stack;
025:
026: /**
027: * A simple thread pool. Idle threads are cached for future use.
028: * The cache grows until it reaches a maximum size (default 10).
029: * When there is nothing in the cache, a new thread is created.
030: * By default the threads are daemon threads.
031: *
032: * <a href="mailto:rickard.oberg@telkel.com">Rickard \u00d6berg</a>
033: * <a href="mailto:adrian.brock@happeningtimes.com">Adrian Brock</a>
034: * @version $Revision: 57200 $
035: */
036: public class ThreadPool {
037: // Constants -----------------------------------------------------
038:
039: // Attributes ----------------------------------------------------
040: private static int counter = 0;
041:
042: /**
043: * Stack of idle threads cached for future use.
044: */
045: private Stack pool = new Stack();
046:
047: /**
048: * Maximum number of idle threads cached in this pool.
049: */
050: private int maxSize = 10;
051:
052: /**
053: * Is the thread pool active
054: */
055: private boolean active = false;
056:
057: /**
058: * Whether the threads are daemon threads.
059: */
060: private boolean daemon = true;
061:
062: // Static --------------------------------------------------------
063:
064: // Constructors --------------------------------------------------
065:
066: /**
067: * Create a new pool.
068: */
069: public ThreadPool() {
070: }
071:
072: /**
073: * Create a new pool with an activity status
074: *
075: * @param active true for active, false otherwise
076: */
077: public ThreadPool(boolean active) {
078: this .active = active;
079: }
080:
081: // Public --------------------------------------------------------
082:
083: /**
084: * Set the maximum number of idle threads cached in this pool.
085: *
086: * @param size the new maximum size.
087: */
088: public void setMaximumSize(int size) {
089: maxSize = size;
090: }
091:
092: /**
093: * Get the maximum number of idle threads cached in this pool.
094: *
095: * @return the maximum size
096: */
097: public int getMaximumSize() {
098: return maxSize;
099: }
100:
101: /**
102: * Set the activity status of the pool. Setting the pool to
103: * inactive, clears the pool.
104: *
105: * @param status pass true for active, false otherwise.
106: */
107: public void setActive(boolean status) {
108: active = status;
109: if (active == false)
110: while (pool.size() > 0)
111: ((Worker) pool.pop()).die();
112: }
113:
114: /**
115: * Get the activity status of the pool.
116: *
117: * @return true for an active pool, false otherwise.
118: */
119: public boolean isActive() {
120: return active;
121: }
122:
123: /**
124: * Set whether new threads are daemon threads.
125: *
126: * @param value pass true for daemon threads, false otherwise.
127: */
128: public void setDaemonThreads(boolean value) {
129: daemon = value;
130: }
131:
132: /**
133: * Get whether new threads are daemon threads.
134: *
135: * @return true for daemon threads, false otherwise.
136: */
137: public boolean getDaemonThreads() {
138: return daemon;
139: }
140:
141: /**
142: * Do some work.
143: * This will either create a new thread to do the work, or
144: * use an existing idle cached thread.
145: *
146: * @param work the work to perform.
147: */
148: public synchronized void run(Runnable work) {
149: if (pool.size() == 0)
150: new Worker(work);
151: else {
152: Worker worker = (Worker) pool.pop();
153: worker.run(work);
154: }
155: }
156:
157: // Private -------------------------------------------------------
158:
159: /**
160: * Put an idle worker thread back in the pool of cached idle threads.
161: * This is called from the worker thread itself. When the cache is
162: * full, the thread is discarded.
163: *
164: * @param worker the worker to return.
165: */
166: private synchronized void returnWorker(Worker worker) {
167: if (pool.size() < maxSize)
168: pool.push(worker);
169: else
170: worker.die();
171: }
172:
173: // Inner classes -------------------------------------------------
174:
175: /**
176: * A worker thread runs a worker.
177: */
178: class Worker extends Thread {
179: /**
180: * Flags that this worker may continue to work.
181: */
182: boolean running = true;
183:
184: /**
185: * Work to do, of <code>null</code> if no work to do.
186: */
187: Runnable work;
188:
189: /**
190: * Create a new Worker to do some work.
191: *
192: * @param work the work to perform
193: */
194: Worker(Runnable work) {
195: // give it a thread so we can figure out what this thread is in debugging
196: super ("ThreadPoolWorker[" + (++counter) + "]");
197: this .work = work;
198: setDaemon(daemon);
199: start();
200: }
201:
202: /**
203: * Tell this worker to die.
204: */
205: public synchronized void die() {
206: running = false;
207: this .notify();
208: }
209:
210: /**
211: * Give this Worker some work to do.
212: *
213: * @param the work to perform.
214: * @throws IllegalStateException If this worker already
215: * has work to do.
216: */
217: public synchronized void run(Runnable work) {
218: if (this .work != null)
219: throw new IllegalStateException(
220: "Worker already has work to do.");
221: this .work = work;
222: this .notify();
223: }
224:
225: /**
226: * The worker loop.
227: */
228: public void run() {
229: while (active && running) {
230: // If work is available then execute it
231: if (work != null) {
232: try {
233: work.run();
234: } catch (Exception ignored) {
235: }
236:
237: // Clear work
238: work = null;
239: }
240:
241: // Return to pool of cached idle threads
242: returnWorker(this );
243:
244: // Wait for more work to become available
245: synchronized (this ) {
246: while (running && work == null) {
247: try {
248: this .wait();
249: } catch (InterruptedException ignored) {
250: }
251: }
252: }
253: }
254: }
255: }
256: }
|