1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.executor;
21
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.LinkedBlockingQueue;
28 import java.util.concurrent.RejectedExecutionHandler;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.ThreadPoolExecutor;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.atomic.AtomicInteger;
33
34 import org.apache.mina.core.session.IoEvent;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class UnorderedThreadPoolExecutor extends ThreadPoolExecutor {
55
56 private static final Runnable EXIT_SIGNAL = new Runnable() {
57 public void run() {
58 throw new Error("This method shouldn't be called. " + "Please file a bug report.");
59 }
60 };
61
62 private final Set<Worker> workers = new HashSet<Worker>();
63
64 private volatile int corePoolSize;
65
66 private volatile int maximumPoolSize;
67
68 private volatile int largestPoolSize;
69
70 private final AtomicInteger idleWorkers = new AtomicInteger();
71
72 private long completedTaskCount;
73
74 private volatile boolean shutdown;
75
76 private final IoEventQueueHandler queueHandler;
77
78 public UnorderedThreadPoolExecutor() {
79 this(16);
80 }
81
82 public UnorderedThreadPoolExecutor(int maximumPoolSize) {
83 this(0, maximumPoolSize);
84 }
85
86 public UnorderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize) {
87 this(corePoolSize, maximumPoolSize, 30, TimeUnit.SECONDS);
88 }
89
90 public UnorderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
91 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory());
92 }
93
94 public UnorderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
95 IoEventQueueHandler queueHandler) {
96 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory(), queueHandler);
97 }
98
99 public UnorderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
100 ThreadFactory threadFactory) {
101 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, threadFactory, null);
102 }
103
104 public UnorderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
105 ThreadFactory threadFactory, IoEventQueueHandler queueHandler) {
106 super(0, 1, keepAliveTime, unit, new LinkedBlockingQueue<Runnable>(), threadFactory, new AbortPolicy());
107 if (corePoolSize < 0) {
108 throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
109 }
110
111 if (maximumPoolSize == 0 || maximumPoolSize < corePoolSize) {
112 throw new IllegalArgumentException("maximumPoolSize: " + maximumPoolSize);
113 }
114
115 if (queueHandler == null) {
116 queueHandler = IoEventQueueHandler.NOOP;
117 }
118
119 this.corePoolSize = corePoolSize;
120 this.maximumPoolSize = maximumPoolSize;
121 this.queueHandler = queueHandler;
122 }
123
124 public IoEventQueueHandler getQueueHandler() {
125 return queueHandler;
126 }
127
128 @Override
129 public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
130
131 }
132
133 private void addWorker() {
134 synchronized (workers) {
135 if (workers.size() >= maximumPoolSize) {
136 return;
137 }
138
139 Worker worker = new Worker();
140 Thread thread = getThreadFactory().newThread(worker);
141 idleWorkers.incrementAndGet();
142 thread.start();
143 workers.add(worker);
144
145 if (workers.size() > largestPoolSize) {
146 largestPoolSize = workers.size();
147 }
148 }
149 }
150
151 private void addWorkerIfNecessary() {
152 if (idleWorkers.get() == 0) {
153 synchronized (workers) {
154 if (workers.isEmpty() || idleWorkers.get() == 0) {
155 addWorker();
156 }
157 }
158 }
159 }
160
161 private void removeWorker() {
162 synchronized (workers) {
163 if (workers.size() <= corePoolSize) {
164 return;
165 }
166 getQueue().offer(EXIT_SIGNAL);
167 }
168 }
169
170 @Override
171 public int getMaximumPoolSize() {
172 return maximumPoolSize;
173 }
174
175 @Override
176 public void setMaximumPoolSize(int maximumPoolSize) {
177 if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) {
178 throw new IllegalArgumentException("maximumPoolSize: " + maximumPoolSize);
179 }
180
181 synchronized (workers) {
182 this.maximumPoolSize = maximumPoolSize;
183 int difference = workers.size() - maximumPoolSize;
184 while (difference > 0) {
185 removeWorker();
186 --difference;
187 }
188 }
189 }
190
191 @Override
192 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
193
194 long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
195
196 synchronized (workers) {
197 while (!isTerminated()) {
198 long waitTime = deadline - System.currentTimeMillis();
199 if (waitTime <= 0) {
200 break;
201 }
202
203 workers.wait(waitTime);
204 }
205 }
206 return isTerminated();
207 }
208
209 @Override
210 public boolean isShutdown() {
211 return shutdown;
212 }
213
214 @Override
215 public boolean isTerminated() {
216 if (!shutdown) {
217 return false;
218 }
219
220 synchronized (workers) {
221 return workers.isEmpty();
222 }
223 }
224
225 @Override
226 public void shutdown() {
227 if (shutdown) {
228 return;
229 }
230
231 shutdown = true;
232
233 synchronized (workers) {
234 for (int i = workers.size(); i > 0; i--) {
235 getQueue().offer(EXIT_SIGNAL);
236 }
237 }
238 }
239
240 @Override
241 public List<Runnable> shutdownNow() {
242 shutdown();
243
244 List<Runnable> answer = new ArrayList<Runnable>();
245 Runnable task;
246 while ((task = getQueue().poll()) != null) {
247 if (task == EXIT_SIGNAL) {
248 getQueue().offer(EXIT_SIGNAL);
249 Thread.yield();
250 continue;
251 }
252
253 getQueueHandler().polled(this, (IoEvent) task);
254 answer.add(task);
255 }
256
257 return answer;
258 }
259
260 @Override
261 public void execute(Runnable task) {
262 if (shutdown) {
263 rejectTask(task);
264 }
265
266 checkTaskType(task);
267
268 IoEvent e = (IoEvent) task;
269 boolean offeredEvent = queueHandler.accept(this, e);
270 if (offeredEvent) {
271 getQueue().offer(e);
272 }
273
274 addWorkerIfNecessary();
275
276 if (offeredEvent) {
277 queueHandler.offered(this, e);
278 }
279 }
280
281 private void rejectTask(Runnable task) {
282 getRejectedExecutionHandler().rejectedExecution(task, this);
283 }
284
285 private void checkTaskType(Runnable task) {
286 if (!(task instanceof IoEvent)) {
287 throw new IllegalArgumentException("task must be an IoEvent or its subclass.");
288 }
289 }
290
291 @Override
292 public int getActiveCount() {
293 synchronized (workers) {
294 return workers.size() - idleWorkers.get();
295 }
296 }
297
298 @Override
299 public long getCompletedTaskCount() {
300 synchronized (workers) {
301 long answer = completedTaskCount;
302 for (Worker w : workers) {
303 answer += w.completedTaskCount;
304 }
305
306 return answer;
307 }
308 }
309
310 @Override
311 public int getLargestPoolSize() {
312 return largestPoolSize;
313 }
314
315 @Override
316 public int getPoolSize() {
317 synchronized (workers) {
318 return workers.size();
319 }
320 }
321
322 @Override
323 public long getTaskCount() {
324 return getCompletedTaskCount();
325 }
326
327 @Override
328 public boolean isTerminating() {
329 synchronized (workers) {
330 return isShutdown() && !isTerminated();
331 }
332 }
333
334 @Override
335 public int prestartAllCoreThreads() {
336 int answer = 0;
337 synchronized (workers) {
338 for (int i = corePoolSize - workers.size(); i > 0; i--) {
339 addWorker();
340 answer++;
341 }
342 }
343 return answer;
344 }
345
346 @Override
347 public boolean prestartCoreThread() {
348 synchronized (workers) {
349 if (workers.size() < corePoolSize) {
350 addWorker();
351 return true;
352 }
353
354 return false;
355 }
356 }
357
358 @Override
359 public void purge() {
360
361 }
362
363 @Override
364 public boolean remove(Runnable task) {
365 boolean removed = super.remove(task);
366 if (removed) {
367 getQueueHandler().polled(this, (IoEvent) task);
368 }
369 return removed;
370 }
371
372 @Override
373 public int getCorePoolSize() {
374 return corePoolSize;
375 }
376
377 @Override
378 public void setCorePoolSize(int corePoolSize) {
379 if (corePoolSize < 0) {
380 throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
381 }
382 if (corePoolSize > maximumPoolSize) {
383 throw new IllegalArgumentException("corePoolSize exceeds maximumPoolSize");
384 }
385
386 synchronized (workers) {
387 if (this.corePoolSize > corePoolSize) {
388 for (int i = this.corePoolSize - corePoolSize; i > 0; i--) {
389 removeWorker();
390 }
391 }
392 this.corePoolSize = corePoolSize;
393 }
394 }
395
396 private class Worker implements Runnable {
397
398 private volatile long completedTaskCount;
399
400 private Thread thread;
401
402 public void run() {
403 thread = Thread.currentThread();
404
405 try {
406 for (;;) {
407 Runnable task = fetchTask();
408
409 idleWorkers.decrementAndGet();
410
411 if (task == null) {
412 synchronized (workers) {
413 if (workers.size() > corePoolSize) {
414
415 workers.remove(this);
416 break;
417 }
418 }
419 }
420
421 if (task == EXIT_SIGNAL) {
422 break;
423 }
424
425 try {
426 if (task != null) {
427 queueHandler.polled(UnorderedThreadPoolExecutor.this, (IoEvent) task);
428 runTask(task);
429 }
430 } finally {
431 idleWorkers.incrementAndGet();
432 }
433 }
434 } finally {
435 synchronized (workers) {
436 workers.remove(this);
437 UnorderedThreadPoolExecutor.this.completedTaskCount += completedTaskCount;
438 workers.notifyAll();
439 }
440 }
441 }
442
443 private Runnable fetchTask() {
444 Runnable task = null;
445 long currentTime = System.currentTimeMillis();
446 long deadline = currentTime + getKeepAliveTime(TimeUnit.MILLISECONDS);
447 for (;;) {
448 try {
449 long waitTime = deadline - currentTime;
450 if (waitTime <= 0) {
451 break;
452 }
453
454 try {
455 task = getQueue().poll(waitTime, TimeUnit.MILLISECONDS);
456 break;
457 } finally {
458 if (task == null) {
459 currentTime = System.currentTimeMillis();
460 }
461 }
462 } catch (InterruptedException e) {
463
464 continue;
465 }
466 }
467 return task;
468 }
469
470 private void runTask(Runnable task) {
471 beforeExecute(thread, task);
472 boolean ran = false;
473 try {
474 task.run();
475 ran = true;
476 afterExecute(task, null);
477 completedTaskCount++;
478 } catch (RuntimeException e) {
479 if (!ran) {
480 afterExecute(task, e);
481 }
482 throw e;
483 }
484 }
485 }
486 }