1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.thread;
16
17 import java.io.Serializable;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Set;
24
25 import org.mortbay.component.AbstractLifeCycle;
26 import org.mortbay.log.Log;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class BoundedThreadPool extends AbstractLifeCycle implements Serializable, ThreadPool
43 {
44 private static int __id;
45 private boolean _daemon;
46 private int _id;
47 private List _idle;
48
49 private final Object _lock = new Object();
50 private final Object _joinLock = new Object();
51
52 private long _lastShrink;
53 private int _maxIdleTimeMs=60000;
54 private int _maxThreads=255;
55 private int _minThreads=1;
56 private String _name;
57 private List _queue;
58 private Set _threads;
59 private boolean _warned=false;
60 int _lowThreads=0;
61 int _priority= Thread.NORM_PRIORITY;
62
63
64
65
66 public BoundedThreadPool()
67 {
68 Log.warn(BoundedThreadPool.class+" deprecated: use "+QueuedThreadPool.class);
69 _name="btpool"+__id++;
70 }
71
72
73
74
75
76 public boolean dispatch(Runnable job)
77 {
78 synchronized(_lock)
79 {
80 if (!isRunning() || job==null)
81 return false;
82
83
84 int idle=_idle.size();
85 if (idle>0)
86 {
87 PoolThread thread=(PoolThread)_idle.remove(idle-1);
88 thread.dispatch(job);
89 }
90 else
91 {
92
93 if (_threads.size()<_maxThreads)
94 {
95
96 newThread(job);
97 }
98 else
99 {
100 if (!_warned)
101 {
102 _warned=true;
103 Log.debug("Out of threads for {}",this);
104 }
105 _queue.add(job);
106 }
107 }
108 }
109
110 return true;
111 }
112
113
114
115
116
117
118 public int getIdleThreads()
119 {
120 return _idle==null?0:_idle.size();
121 }
122
123
124
125
126
127 public int getLowThreads()
128 {
129 return _lowThreads;
130 }
131
132
133
134
135
136
137
138
139 public int getMaxIdleTimeMs()
140 {
141 return _maxIdleTimeMs;
142 }
143
144
145
146
147
148
149
150 public int getMaxThreads()
151 {
152 return _maxThreads;
153 }
154
155
156
157
158
159
160
161 public int getMinThreads()
162 {
163 return _minThreads;
164 }
165
166
167
168
169
170 public String getName()
171 {
172 return _name;
173 }
174
175
176
177
178
179
180 public int getThreads()
181 {
182 return _threads.size();
183 }
184
185
186
187
188
189 public int getThreadsPriority()
190 {
191 return _priority;
192 }
193
194
195 public int getQueueSize()
196 {
197 synchronized(_lock)
198 {
199 return _queue.size();
200 }
201 }
202
203
204
205
206
207 public boolean isDaemon()
208 {
209 return _daemon;
210 }
211
212
213 public boolean isLowOnThreads()
214 {
215 synchronized(_lock)
216 {
217
218 return _queue.size()>_lowThreads;
219 }
220 }
221
222
223 public void join() throws InterruptedException
224 {
225 synchronized (_joinLock)
226 {
227 while (isRunning())
228 _joinLock.wait();
229 }
230
231
232 while (isStopping())
233 Thread.sleep(10);
234 }
235
236
237
238
239
240 public void setDaemon(boolean daemon)
241 {
242 _daemon=daemon;
243 }
244
245
246
247
248
249 public void setLowThreads(int lowThreads)
250 {
251 _lowThreads = lowThreads;
252 }
253
254
255
256
257
258
259
260
261
262 public void setMaxIdleTimeMs(int maxIdleTimeMs)
263 {
264 _maxIdleTimeMs=maxIdleTimeMs;
265 }
266
267
268
269
270
271
272
273 public void setMaxThreads(int maxThreads)
274 {
275 if (isStarted() && maxThreads<_minThreads)
276 throw new IllegalArgumentException("!minThreads<maxThreads");
277 _maxThreads=maxThreads;
278 }
279
280
281
282
283
284
285
286 public void setMinThreads(int minThreads)
287 {
288 if (isStarted() && (minThreads<=0 || minThreads>_maxThreads))
289 throw new IllegalArgumentException("!0<=minThreads<maxThreads");
290 _minThreads=minThreads;
291 synchronized (_lock)
292 {
293 while (isStarted() && _threads.size()<_minThreads)
294 {
295 newThread(null);
296 }
297 }
298 }
299
300
301
302
303
304 public void setName(String name)
305 {
306 _name= name;
307 }
308
309
310
311
312
313 public void setThreadsPriority(int priority)
314 {
315 _priority=priority;
316 }
317
318
319
320
321
322 protected void doStart() throws Exception
323 {
324 if (_maxThreads<_minThreads || _minThreads<=0)
325 throw new IllegalArgumentException("!0<minThreads<maxThreads");
326
327 _threads=new HashSet();
328 _idle=new ArrayList();
329 _queue=new LinkedList();
330
331 for (int i=0;i<_minThreads;i++)
332 {
333 newThread(null);
334 }
335 }
336
337
338
339
340
341
342
343
344
345 protected void doStop() throws Exception
346 {
347 super.doStop();
348
349 for (int i=0;i<100;i++)
350 {
351 synchronized (_lock)
352 {
353 Iterator iter = _threads.iterator();
354 while (iter.hasNext())
355 ((Thread)iter.next()).interrupt();
356 }
357
358 Thread.yield();
359 if (_threads.size()==0)
360 break;
361
362 try
363 {
364 Thread.sleep(i*100);
365 }
366 catch(InterruptedException e){}
367 }
368
369
370 if (_threads.size()>0)
371 Log.warn(_threads.size()+" threads could not be stopped");
372
373 synchronized (_joinLock)
374 {
375 _joinLock.notifyAll();
376 }
377 }
378
379
380 protected PoolThread newThread(Runnable job)
381 {
382 synchronized(_lock)
383 {
384 PoolThread thread =new PoolThread(job);
385 _threads.add(thread);
386 thread.setName(_name+"-"+_id++);
387 thread.start();
388 return thread;
389 }
390 }
391
392
393
394
395
396
397
398
399
400 protected void stopJob(Thread thread, Object job)
401 {
402 thread.interrupt();
403 }
404
405
406
407
408
409
410
411 public class PoolThread extends Thread
412 {
413 Runnable _job=null;
414
415
416 PoolThread()
417 {
418 setDaemon(_daemon);
419 setPriority(_priority);
420 }
421
422
423 PoolThread(Runnable job)
424 {
425 setDaemon(_daemon);
426 setPriority(_priority);
427 _job=job;
428 }
429
430
431
432
433
434 public void run()
435 {
436 try
437 {
438 Runnable job=null;
439
440 synchronized (this)
441 {
442 job=_job;
443 _job=null;
444 }
445
446 while (isRunning())
447 {
448 if (job!=null)
449 {
450 Runnable todo=job;
451 job=null;
452 todo.run();
453 }
454 else
455 {
456
457 synchronized (_lock)
458 {
459
460 if (_queue.size()>0)
461 {
462 job=(Runnable)_queue.remove(0);
463 continue;
464 }
465 else
466 {
467 _warned=false;
468
469
470 if (_threads.size()>_maxThreads ||
471 _idle.size()>0 &&
472 _threads.size()>_minThreads)
473 {
474 long now = System.currentTimeMillis();
475 if ((now-_lastShrink)>getMaxIdleTimeMs())
476 {
477 _lastShrink=now;
478 return;
479 }
480 }
481 }
482
483
484 _idle.add(this);
485 }
486
487 try
488 {
489 synchronized (this)
490 {
491 if (_job==null)
492 this.wait(getMaxIdleTimeMs());
493 job=_job;
494 _job=null;
495 }
496 }
497 catch (InterruptedException e)
498 {
499 Log.ignore(e);
500 }
501 finally
502 {
503 synchronized (_lock)
504 {
505 _idle.remove(this);
506 }
507 }
508 }
509 }
510 }
511 finally
512 {
513 synchronized (_lock)
514 {
515 _threads.remove(this);
516 }
517
518 Runnable job=null;
519 synchronized (this)
520 {
521 job=_job;
522 }
523 if (job!=null && isRunning())
524 BoundedThreadPool.this.dispatch(job);
525 }
526 }
527
528
529 void dispatch(Runnable job)
530 {
531 synchronized (this)
532 {
533 if(_job!=null || job==null)
534 throw new IllegalStateException();
535 _job=job;
536 this.notify();
537 }
538 }
539 }
540
541 }