KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > util > WorkThreadPool


1 /*
2  * WorkThreadPool.java - Background thread pool that does stuff
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2000 Slava Pestov
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */

22
23 package org.gjt.sp.util;
24
25 //{{{ Imports
26
import javax.swing.event.EventListenerList JavaDoc;
27 import javax.swing.SwingUtilities JavaDoc;
28 //}}}
29

30 /**
31  * A pool of work threads.
32  * @author Slava Pestov
33  * @version $Id: WorkThreadPool.java 5053 2004-05-29 01:55:26Z spestov $
34  * @see org.gjt.sp.util.WorkThread
35  * @since jEdit 2.6pre1
36  */

37 public class WorkThreadPool
38 {
39     //{{{ WorkThreadPool constructor
40
/**
41      * Creates a new work thread pool with the specified number of
42      * work threads.
43      * @param name The thread name prefix
44      * @param count The number of work threads
45      */

46     public WorkThreadPool(String JavaDoc name, int count)
47     {
48         listenerList = new EventListenerList JavaDoc();
49
50         if(count != 0)
51         {
52             threadGroup = new ThreadGroup JavaDoc(name);
53             threads = new WorkThread[count];
54             for(int i = 0; i < threads.length; i++)
55             {
56                 threads[i] = new WorkThread(this,threadGroup,name + " #" + (i+1));
57             }
58         }
59         else
60             Log.log(Log.WARNING,this,"Async I/O disabled");
61     } //}}}
62

63     //{{{ start() method
64
/**
65      * Starts all the threads in this thread pool.
66      */

67     public void start()
68     {
69         /* not really needed since threads don't start until after */
70         synchronized(lock)
71         {
72             started = true;
73
74             if(awtRequestCount != 0 && requestCount == 0)
75                 queueAWTRunner();
76         }
77
78         if(threads != null)
79         {
80             for(int i = 0; i < threads.length; i++)
81             {
82                 threads[i].start();
83             }
84         }
85     } //}}}
86

87     //{{{ addWorkRequest() method
88
/**
89      * Adds a work request to the queue.
90      * @param run The runnable
91      * @param inAWT If true, will be executed in AWT thread. Otherwise,
92      * will be executed in work thread
93      */

94     public void addWorkRequest(Runnable JavaDoc run, boolean inAWT)
95     {
96         if(threads == null)
97         {
98             run.run();
99             return;
100         }
101
102         synchronized(lock)
103         {
104             //{{{ if there are no requests, execute AWT requests immediately
105
if(started && inAWT && requestCount == 0 && awtRequestCount == 0)
106             {
107 // Log.log(Log.DEBUG,this,"AWT immediate: " + run);
108

109                 if(SwingUtilities.isEventDispatchThread())
110                     run.run();
111                 else
112                     SwingUtilities.invokeLater(run);
113
114                 return;
115             } //}}}
116

117             Request request = new Request(run);
118
119             //{{{ Add to AWT queue...
120
if(inAWT)
121             {
122                 if(firstAWTRequest == null && lastAWTRequest == null)
123                     firstAWTRequest = lastAWTRequest = request;
124                 else
125                 {
126                     lastAWTRequest.next = request;
127                     lastAWTRequest = request;
128                 }
129
130                 awtRequestCount++;
131
132                 // if no requests are running, requestDone()
133
// will not be called, so we must queue the
134
// AWT runner ourselves.
135
if(started && requestCount == 0)
136                     queueAWTRunner();
137             } //}}}
138
//{{{ Add to work thread queue...
139
else
140             {
141                 if(firstRequest == null && lastRequest == null)
142                     firstRequest = lastRequest = request;
143                 else
144                 {
145                     lastRequest.next = request;
146                     lastRequest = request;
147                 }
148
149                 requestCount++;
150             } //}}}
151

152             lock.notifyAll();
153         }
154     } //}}}
155

156     //{{{ waitForRequests() method
157
/**
158      * Waits until all requests are complete.
159      */

160     public void waitForRequests()
161     {
162         if(threads == null)
163             return;
164
165         synchronized(waitForAllLock)
166         {
167             while(requestCount != 0)
168             {
169                 try
170                 {
171                     waitForAllLock.wait();
172                 }
173                 catch(InterruptedException JavaDoc ie)
174                 {
175                     Log.log(Log.ERROR,this,ie);
176                 }
177             }
178         }
179
180         if(SwingUtilities.isEventDispatchThread())
181         {
182             // do any queued AWT runnables
183
doAWTRequests();
184         }
185         else
186         {
187             try
188             {
189                 SwingUtilities.invokeAndWait(new RunRequestsInAWTThread());
190             }
191             catch(Exception JavaDoc e)
192             {
193                 Log.log(Log.ERROR,this,e);
194             }
195         }
196     } //}}}
197

198     //{{{ getRequestCount() method
199
/**
200      * Returns the number of pending requests.
201      */

202     public int getRequestCount()
203     {
204         return requestCount;
205     } //}}}
206

207     //{{{ getThreadCount() method
208
/**
209      * Returns the number of threads in this pool.
210      */

211     public int getThreadCount()
212     {
213         if(threads == null)
214             return 0;
215         else
216             return threads.length;
217     } //}}}
218

219     //{{{ getThread() method
220
/**
221      * Returns the specified thread.
222      * @param index The index of the thread
223      */

224     public WorkThread getThread(int index)
225     {
226         return threads[index];
227     } //}}}
228

229     //{{{ addProgressListener() method
230
/**
231      * Adds a progress listener to this thread pool.
232      * @param listener The listener
233      */

234     public void addProgressListener(WorkThreadProgressListener listener)
235     {
236         listenerList.add(WorkThreadProgressListener.class,listener);
237     } //}}}
238

239     //{{{ removeProgressListener() method
240
/**
241      * Removes a progress listener from this thread pool.
242      * @param listener The listener
243      */

244     public void removeProgressListener(WorkThreadProgressListener listener)
245     {
246         listenerList.remove(WorkThreadProgressListener.class,listener);
247     } //}}}
248

249     //{{{ Package-private members
250
Object JavaDoc lock = new Object JavaDoc();
251     Object JavaDoc waitForAllLock = new Object JavaDoc();
252
253     //{{{ fireStatusChanged() method
254
void fireStatusChanged(WorkThread thread)
255     {
256         final Object JavaDoc[] listeners = listenerList.getListenerList();
257         if(listeners.length != 0)
258         {
259             int index = 0;
260             for(int i = 0; i < threads.length; i++)
261             {
262                 if(threads[i] == thread)
263                 {
264                     index = i;
265                     break;
266                 }
267             }
268
269             for(int i = listeners.length - 2; i >= 0; i--)
270             {
271                 if(listeners[i] == WorkThreadProgressListener.class)
272                 {
273                     ((WorkThreadProgressListener)listeners[i+1])
274                         .statusUpdate(WorkThreadPool.this,index);
275                 }
276             }
277         }
278     } //}}}
279

280     //{{{ fireProgressChanged() method
281
void fireProgressChanged(WorkThread thread)
282     {
283         final Object JavaDoc[] listeners = listenerList.getListenerList();
284         if(listeners.length != 0)
285         {
286             int index = 0;
287             for(int i = 0; i < threads.length; i++)
288             {
289                 if(threads[i] == thread)
290                 {
291                     index = i;
292                     break;
293                 }
294             }
295
296             for(int i = listeners.length - 2; i >= 0; i--)
297             {
298                 if(listeners[i] == WorkThreadProgressListener.class)
299                 {
300                     ((WorkThreadProgressListener)listeners[i+1])
301                         .progressUpdate(WorkThreadPool.this,index);
302                 }
303             }
304         }
305     } //}}}
306

307     //{{{ requestDone() method
308
void requestDone()
309     {
310         synchronized(lock)
311         {
312             requestCount--;
313
314             if(requestCount == 0 && firstAWTRequest != null)
315                 queueAWTRunner();
316         }
317     } //}}}
318

319     //{{{ getNextRequest() method
320
Request getNextRequest()
321     {
322         synchronized(lock)
323         {
324             Request request = firstRequest;
325             if(request == null)
326                 return null;
327
328             firstRequest = firstRequest.next;
329             if(firstRequest == null)
330                 lastRequest = null;
331
332             if(request.alreadyRun)
333                 throw new InternalError JavaDoc("AIEE!!! Request run twice!!! " + request.run);
334             request.alreadyRun = true;
335
336             /* StringBuffer buf = new StringBuffer("request queue is now: ");
337             Request _request = request.next;
338             while(_request != null)
339             {
340                 buf.append(_request.id);
341                 if(_request.next != null)
342                     buf.append(",");
343                 _request = _request.next;
344             }
345             Log.log(Log.DEBUG,this,buf.toString()); */

346
347             return request;
348         }
349     } //}}}
350

351     //}}}
352

353     //{{{ Private members
354

355     //{{{ Instance variables
356
private boolean started;
357     private ThreadGroup JavaDoc threadGroup;
358     private WorkThread[] threads;
359
360     // Request queue
361
private Request firstRequest;
362     private Request lastRequest;
363     private int requestCount;
364
365     // AWT thread magic
366
private boolean awtRunnerQueued;
367     private Request firstAWTRequest;
368     private Request lastAWTRequest;
369     private int awtRequestCount;
370
371     private EventListenerList JavaDoc listenerList;
372     //}}}
373

374     //{{{ doAWTRequests() method
375
/** Must always be called with the lock held. */
376     private void doAWTRequests()
377     {
378         while(requestCount == 0 && firstAWTRequest != null)
379         {
380             doAWTRequest(getNextAWTRequest());
381         }
382     } //}}}
383

384     //{{{ doAWTRequest() method
385
/** Must always be called with the lock held. */
386     private void doAWTRequest(Request request)
387     {
388 // Log.log(Log.DEBUG,this,"Running in AWT thread: " + request);
389

390         try
391         {
392             request.run.run();
393         }
394         catch(Throwable JavaDoc t)
395         {
396             Log.log(Log.ERROR,WorkThread.class,"Exception "
397                 + "in AWT thread:");
398             Log.log(Log.ERROR,WorkThread.class,t);
399         }
400
401         awtRequestCount--;
402     } //}}}
403

404     //{{{ queueAWTRunner() method
405
/** Must always be called with the lock held. */
406     private void queueAWTRunner()
407     {
408         if(!awtRunnerQueued)
409         {
410             awtRunnerQueued = true;
411             SwingUtilities.invokeLater(new RunRequestsInAWTThread());
412 // Log.log(Log.DEBUG,this,"AWT runner queued");
413
}
414     } //}}}
415

416     //{{{ getNextAWTRequest() method
417
private Request getNextAWTRequest()
418     {
419         Request request = firstAWTRequest;
420         firstAWTRequest = firstAWTRequest.next;
421         if(firstAWTRequest == null)
422             lastAWTRequest = null;
423
424         if(request.alreadyRun)
425             throw new InternalError JavaDoc("AIEE!!! Request run twice!!! " + request.run);
426         request.alreadyRun = true;
427
428         /* StringBuffer buf = new StringBuffer("AWT request queue is now: ");
429         Request _request = request.next;
430         while(_request != null)
431         {
432             buf.append(_request.id);
433             if(_request.next != null)
434                 buf.append(",");
435             _request = _request.next;
436         }
437         Log.log(Log.DEBUG,this,buf.toString()); */

438
439         return request;
440     } //}}}
441

442     //}}}
443

444     static int ID;
445
446     //{{{ Request class
447
static class Request
448     {
449         int id = ++ID;
450
451         Runnable JavaDoc run;
452
453         boolean alreadyRun;
454
455         Request next;
456
457         Request(Runnable JavaDoc run)
458         {
459             this.run = run;
460         }
461
462         public String JavaDoc toString()
463         {
464             return "[id=" + id + ",run=" + run + "]";
465         }
466     } //}}}
467

468     //{{{ RunRequestsInAWTThread class
469
class RunRequestsInAWTThread implements Runnable JavaDoc
470     {
471         public void run()
472         {
473             synchronized(lock)
474             {
475                 awtRunnerQueued = false;
476                 if(requestCount == 0)
477                     doAWTRequests();
478             }
479         }
480     } //}}}
481
}
482
Popular Tags