KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > exolab > jms > common > threads > ThreadPool


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 2000-2004 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: ThreadPool.java,v 1.1 2004/11/26 01:50:35 tanderson Exp $
44  */

45 package org.exolab.jms.common.threads;
46
47 import org.exolab.jms.common.util.FifoQueue;
48
49
50 /**
51  * Thread manager that maintains a list of worker threads and allocates
52  * them to execute objects asynchronously. This enables execution without the
53  * overhead of thread creation.
54  * <p>
55  * The thread pool is constructed with a fixed number of threads.
56  * The number of threads cannot be increased after the pool is created, but
57  * there can be multiple thread pools.
58  * <p>
59  * There are two methods to execute threads:
60  * <ul>
61  * <li>{@link #execute} - this executes an {@link Runnable} object using
62  * the first available worker thread. If no threads are available,
63  * the call blocks until one is free.</li>
64  * <li>{@link #queue} - this queues an {@link Runnable} object for later
65  * execution by the first available worker thread. It returns immediately
66  * without blocking.</li>
67  * </ul>
68  *
69  * @version $Revision: 1.1 $ $Date: 2004/11/26 01:50:35 $
70  * @author <a HREF="mailto:mourikis@exolab.org">Jim Mourikis</a>
71  * @see CompletionListener
72  */

73 public class ThreadPool {
74
75     /**
76      * The name of this thread pool
77      */

78     private final String JavaDoc _name;
79
80     /**
81      * The thread group of this pool
82      */

83     private ThreadGroup JavaDoc _group;
84
85     /**
86      * The list of idle threads ready for use
87      */

88     private FifoQueue _idleWorkers;
89
90     /**
91      * The list of all worker threads, working or idle
92      */

93     private ThreadPoolWorker[] _workers;
94
95     /**
96      * The queue of pending {@link Runnable} instances
97      */

98     private QueueWorker _queue;
99
100     /**
101      * Seed value for creating unique thread pool names
102      */

103     private static volatile int _poolSeed = 0;
104
105
106     /**
107      * Create a new thread pool with the requested number of threads.
108      * Each thread will be allocated to a new ThreadGroup named
109      * 'ThreadPool-'<id> where id is a number incremented for each new thread
110      * pool.
111      *
112      * @param threads the number of threads to allocate to the pool
113      * @throws IllegalArgumentException if the number of threads is less than 1
114      */

115     public ThreadPool(int threads) {
116         this(threads, false);
117     }
118
119     /**
120      * Create a new thread pool with the requested number of threads.
121      * Each thread will be allocated to a new ThreadGroup named
122      * 'ThreadPool-'<id> where id is a number incremented for each new thread
123      * pool.
124      *
125      * @param threads the number of threads to allocate to the pool
126      * @param daemon if <code>true</code> all threads will be daemon threads
127      * @throws IllegalArgumentException if the number of threads is less than 1
128      */

129     public ThreadPool(int threads, boolean daemon) {
130         this("ThreadPool-" + ++_poolSeed, threads, daemon);
131     }
132
133     /**
134      * Create a new thread pool with the requested number of threads.
135      * Each thread will be allocated to a new ThreadGroup with the specified
136      * name.
137      *
138      * @param name the name of the thread group
139      * @param threads the number of threads to allocate to the pool
140      * @throws IllegalArgumentException if the number of threads is less than 1
141      */

142     public ThreadPool(String JavaDoc name, int threads) {
143         this(name, threads, false);
144     }
145
146     /**
147      * Create a new thread pool with the requested number of threads.
148      * Each thread will be allocated to a new ThreadGroup with the specified
149      * name.
150      *
151      * @param name the name of the thread group
152      * @param threads the number of threads to allocate to the pool
153      * @param daemon if <code>true</code> all threads will be daemon threads
154      * @throws IllegalArgumentException if the number of threads is less than 1
155      */

156     public ThreadPool(String JavaDoc name, int threads, boolean daemon) {
157         this(new ThreadGroup JavaDoc(name), threads, daemon);
158     }
159
160     /**
161      * Create a new thread pool with the requested number of threads.
162      * Each thread will be associated with the supplied thread group.
163      *
164      * @param group the thread group
165      * @param threads the number of threads to allocate to the pool
166      * @param daemon if <code>true</code> all threads will be daemon threads
167      * @throws IllegalArgumentException if the number of threads is less than 1
168      */

169     public ThreadPool(ThreadGroup JavaDoc group, int threads, boolean daemon) {
170         _name = group.getName();
171         _group = new ThreadGroup JavaDoc(_name);
172         if (daemon) {
173             _group.setDaemon(true);
174         }
175         if (threads < 1) {
176             throw new IllegalArgumentException JavaDoc(
177                 "Argument 'threads' must be > 0");
178         }
179
180         _idleWorkers = new FifoQueue(threads);
181         _workers = new ThreadPoolWorker[threads];
182
183         for (int i = 0; i < _workers.length; ++i) {
184             String JavaDoc id = _name + "-Worker-" + i;
185             _workers[i] = new ThreadPoolWorker(_group, id, _idleWorkers);
186         }
187     }
188
189     /**
190      * Execute the {@link Runnable} object using the next available
191      * worker thread. This method will block until a worker thread is
192      * available for use - once a worker thread becomes available it
193      * will return immediately.
194      *
195      * @param target the work to perform
196      * @throws InterruptedException if this thread is interrupted externally
197      */

198     public void execute(Runnable JavaDoc target) throws InterruptedException JavaDoc {
199         // block (forever) until a worker is available
200
ThreadPoolWorker worker = (ThreadPoolWorker) _idleWorkers.get();
201         worker.process(target);
202     }
203
204     /**
205      * Queue the {@link Runnable} object for execution using the next
206      * available worker thread.<br/>
207      * Unlike {@link #execute}, this method does not block.
208      *
209      * @param target the work to perform
210      */

211     public void queue(Runnable JavaDoc target) {
212         queue(target, null);
213     }
214
215     /**
216      * Queue the {@link Runnable} object for execution using the next
217      * available worker thread. When the object completes execution, the
218      * completion listener will be notified.<br/>
219      * Unlike {@link #execute}, this method does not block.
220      *
221      * @param target the work to perform
222      * @param listener the listener to notify when the object has completed
223      * executing
224      */

225     public synchronized void queue(Runnable JavaDoc target,
226                                    CompletionListener listener) {
227         if (_queue == null) {
228             _queue = new QueueWorker(this, _group, _name + "-QueueWorker");
229         }
230         _queue.add(target, listener);
231     }
232
233     /**
234      * Shuts down and removes any idle threads from the queue.
235      * Working threads will not be shutdown.
236      * As working threads finish, and are added back to the idle queue
237      * this call needs to be made again to shut them down and remove them.
238      */

239     public void stopRequestIdleWorkers() {
240         try {
241             Object JavaDoc[] idle = _idleWorkers.getAll();
242             for (int i = 0; i < idle.length; i++) {
243                 ((ThreadPoolWorker) idle[i]).stopRequest();
244             }
245         } catch (InterruptedException JavaDoc exception) {
246             // re-assert
247
Thread.currentThread().interrupt();
248         }
249     }
250
251     /**
252      * Shuts down and removes all threads.
253      * First all idle threads are removed and shutdown,
254      * then all remaining work threads, are shutdown.
255      */

256     public void stopRequestAllWorkers() {
257         final long delay = 250;
258         stopRequestIdleWorkers();
259
260         // give the idle workers a quick chance to die
261
try {
262             Thread.sleep(delay);
263         } catch (InterruptedException JavaDoc ignore) {
264         }
265
266         for (int i = 0; i < _workers.length; i++) {
267             if (_workers[i].isAlive()) {
268                 _workers[i].stopRequest();
269             }
270         }
271
272         if (_queue != null && _queue.isAlive()) {
273             _queue.stop();
274         }
275     }
276
277     /**
278      * Determines if there is at least one idle thread.
279      * This never blocks.
280      *
281      * @return <code>true</code> if there are one or more idle threads
282      */

283     boolean hasIdleThread() {
284         return (_idleWorkers.isEmpty() ? false : true);
285     }
286
287 }
288
Popular Tags