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.Queue;
26 import java.util.Set;
27 import java.util.concurrent.BlockingQueue;
28 import java.util.concurrent.ConcurrentLinkedQueue;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.LinkedBlockingQueue;
31 import java.util.concurrent.RejectedExecutionHandler;
32 import java.util.concurrent.SynchronousQueue;
33 import java.util.concurrent.ThreadFactory;
34 import java.util.concurrent.ThreadPoolExecutor;
35 import java.util.concurrent.TimeUnit;
36 import java.util.concurrent.atomic.AtomicInteger;
37
38 import org.apache.mina.core.session.AttributeKey;
39 import org.apache.mina.core.session.DummySession;
40 import org.apache.mina.core.session.IoEvent;
41 import org.apache.mina.core.session.IoSession;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49
50
51
52
53
54 public class OrderedThreadPoolExecutor extends ThreadPoolExecutor {
55
56 static Logger LOGGER = LoggerFactory.getLogger(OrderedThreadPoolExecutor.class);
57
58
59 private static final int DEFAULT_INITIAL_THREAD_POOL_SIZE = 0;
60
61
62 private static final int DEFAULT_MAX_THREAD_POOL = 16;
63
64
65 private static final int DEFAULT_KEEP_ALIVE = 30;
66
67 private static final IoSession EXIT_SIGNAL = new DummySession();
68
69
70 private final AttributeKey TASKS_QUEUE = new AttributeKey(getClass(), "tasksQueue");
71
72
73 private final BlockingQueue<IoSession> waitingSessions = new LinkedBlockingQueue<IoSession>();
74
75 private final Set<Worker> workers = new HashSet<Worker>();
76
77 private volatile int largestPoolSize;
78
79 private final AtomicInteger idleWorkers = new AtomicInteger();
80
81 private long completedTaskCount;
82
83 private volatile boolean shutdown;
84
85 private final IoEventQueueHandler eventQueueHandler;
86
87
88
89
90
91
92
93
94
95 public OrderedThreadPoolExecutor() {
96 this(DEFAULT_INITIAL_THREAD_POOL_SIZE, DEFAULT_MAX_THREAD_POOL, DEFAULT_KEEP_ALIVE, TimeUnit.SECONDS, Executors
97 .defaultThreadFactory(), null);
98 }
99
100
101
102
103
104
105
106
107
108
109 public OrderedThreadPoolExecutor(int maximumPoolSize) {
110 this(DEFAULT_INITIAL_THREAD_POOL_SIZE, maximumPoolSize, DEFAULT_KEEP_ALIVE, TimeUnit.SECONDS, Executors
111 .defaultThreadFactory(), null);
112 }
113
114
115
116
117
118
119
120
121
122
123 public OrderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize) {
124 this(corePoolSize, maximumPoolSize, DEFAULT_KEEP_ALIVE, TimeUnit.SECONDS, Executors.defaultThreadFactory(),
125 null);
126 }
127
128
129
130
131
132
133
134
135
136
137
138 public OrderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
139 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory(), null);
140 }
141
142
143
144
145
146
147
148
149
150
151
152 public OrderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
153 IoEventQueueHandler eventQueueHandler) {
154 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory(), eventQueueHandler);
155 }
156
157
158
159
160
161
162
163
164
165
166
167 public OrderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
168 ThreadFactory threadFactory) {
169 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, threadFactory, null);
170 }
171
172
173
174
175
176
177
178
179
180
181
182 public OrderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
183 ThreadFactory threadFactory, IoEventQueueHandler eventQueueHandler) {
184
185
186
187 super(DEFAULT_INITIAL_THREAD_POOL_SIZE, 1, keepAliveTime, unit, new SynchronousQueue<Runnable>(),
188 threadFactory, new AbortPolicy());
189
190 if (corePoolSize < DEFAULT_INITIAL_THREAD_POOL_SIZE) {
191 throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
192 }
193
194 if ((maximumPoolSize == 0) || (maximumPoolSize < corePoolSize)) {
195 throw new IllegalArgumentException("maximumPoolSize: " + maximumPoolSize);
196 }
197
198
199 super.setCorePoolSize(corePoolSize);
200 super.setMaximumPoolSize(maximumPoolSize);
201
202
203 if (eventQueueHandler == null) {
204 this.eventQueueHandler = IoEventQueueHandler.NOOP;
205 } else {
206 this.eventQueueHandler = eventQueueHandler;
207 }
208 }
209
210
211
212
213 private SessionTasksQueue getSessionTasksQueue(IoSession session) {
214 SessionTasksQueue queue = (SessionTasksQueue) session.getAttribute(TASKS_QUEUE);
215
216 if (queue == null) {
217 queue = new SessionTasksQueue();
218 SessionTasksQueue oldQueue = (SessionTasksQueue) session.setAttributeIfAbsent(TASKS_QUEUE, queue);
219
220 if (oldQueue != null) {
221 queue = oldQueue;
222 }
223 }
224
225 return queue;
226 }
227
228
229
230
231 public IoEventQueueHandler getQueueHandler() {
232 return eventQueueHandler;
233 }
234
235
236
237
238 @Override
239 public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
240
241 }
242
243
244
245
246
247 private void addWorker() {
248 synchronized (workers) {
249 if (workers.size() >= super.getMaximumPoolSize()) {
250 return;
251 }
252
253
254 Worker worker = new Worker();
255 Thread thread = getThreadFactory().newThread(worker);
256
257
258 idleWorkers.incrementAndGet();
259
260
261 thread.start();
262 workers.add(worker);
263
264 if (workers.size() > largestPoolSize) {
265 largestPoolSize = workers.size();
266 }
267 }
268 }
269
270
271
272
273 private void addWorkerIfNecessary() {
274 if (idleWorkers.get() == 0) {
275 synchronized (workers) {
276 if (workers.isEmpty() || (idleWorkers.get() == 0)) {
277 addWorker();
278 }
279 }
280 }
281 }
282
283 private void removeWorker() {
284 synchronized (workers) {
285 if (workers.size() <= super.getCorePoolSize()) {
286 return;
287 }
288 waitingSessions.offer(EXIT_SIGNAL);
289 }
290 }
291
292
293
294
295 @Override
296 public int getMaximumPoolSize() {
297 return super.getMaximumPoolSize();
298 }
299
300
301
302
303 @Override
304 public void setMaximumPoolSize(int maximumPoolSize) {
305 if ((maximumPoolSize <= 0) || (maximumPoolSize < super.getCorePoolSize())) {
306 throw new IllegalArgumentException("maximumPoolSize: " + maximumPoolSize);
307 }
308
309 synchronized (workers) {
310 super.setMaximumPoolSize(maximumPoolSize);
311 int difference = workers.size() - maximumPoolSize;
312 while (difference > 0) {
313 removeWorker();
314 --difference;
315 }
316 }
317 }
318
319
320
321
322 @Override
323 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
324
325 long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
326
327 synchronized (workers) {
328 while (!isTerminated()) {
329 long waitTime = deadline - System.currentTimeMillis();
330 if (waitTime <= 0) {
331 break;
332 }
333
334 workers.wait(waitTime);
335 }
336 }
337 return isTerminated();
338 }
339
340
341
342
343 @Override
344 public boolean isShutdown() {
345 return shutdown;
346 }
347
348
349
350
351 @Override
352 public boolean isTerminated() {
353 if (!shutdown) {
354 return false;
355 }
356
357 synchronized (workers) {
358 return workers.isEmpty();
359 }
360 }
361
362
363
364
365 @Override
366 public void shutdown() {
367 if (shutdown) {
368 return;
369 }
370
371 shutdown = true;
372
373 synchronized (workers) {
374 for (int i = workers.size(); i > 0; i--) {
375 waitingSessions.offer(EXIT_SIGNAL);
376 }
377 }
378 }
379
380
381
382
383 @Override
384 public List<Runnable> shutdownNow() {
385 shutdown();
386
387 List<Runnable> answer = new ArrayList<Runnable>();
388 IoSession session;
389
390 while ((session = waitingSessions.poll()) != null) {
391 if (session == EXIT_SIGNAL) {
392 waitingSessions.offer(EXIT_SIGNAL);
393 Thread.yield();
394 continue;
395 }
396
397 SessionTasksQueue sessionTasksQueue = (SessionTasksQueue) session.getAttribute(TASKS_QUEUE);
398
399 synchronized (sessionTasksQueue.tasksQueue) {
400
401 for (Runnable task : sessionTasksQueue.tasksQueue) {
402 getQueueHandler().polled(this, (IoEvent) task);
403 answer.add(task);
404 }
405
406 sessionTasksQueue.tasksQueue.clear();
407 }
408 }
409
410 return answer;
411 }
412
413
414
415
416 private void print(Queue<Runnable> queue, IoEvent event) {
417 StringBuilder sb = new StringBuilder();
418 sb.append("Adding event ").append(event.getType()).append(" to session ").append(event.getSession().getId());
419 boolean first = true;
420 sb.append("\nQueue : [");
421 for (Runnable elem : queue) {
422 if (first) {
423 first = false;
424 } else {
425 sb.append(", ");
426 }
427
428 sb.append(((IoEvent) elem).getType()).append(", ");
429 }
430 sb.append("]\n");
431 LOGGER.debug(sb.toString());
432 }
433
434
435
436
437 @Override
438 public void execute(Runnable task) {
439 if (shutdown) {
440 rejectTask(task);
441 }
442
443
444 checkTaskType(task);
445
446 IoEvent event = (IoEvent) task;
447
448
449 IoSession session = event.getSession();
450
451
452 SessionTasksQueue sessionTasksQueue = getSessionTasksQueue(session);
453 Queue<Runnable> tasksQueue = sessionTasksQueue.tasksQueue;
454
455 boolean offerSession;
456
457
458
459
460 boolean offerEvent = eventQueueHandler.accept(this, event);
461
462 if (offerEvent) {
463
464 synchronized (tasksQueue) {
465
466 tasksQueue.offer(event);
467
468 if (sessionTasksQueue.processingCompleted) {
469 sessionTasksQueue.processingCompleted = false;
470 offerSession = true;
471 } else {
472 offerSession = false;
473 }
474
475 if (LOGGER.isDebugEnabled()) {
476 print(tasksQueue, event);
477 }
478 }
479 } else {
480 offerSession = false;
481 }
482
483 if (offerSession) {
484
485
486
487 waitingSessions.offer(session);
488 }
489
490 addWorkerIfNecessary();
491
492 if (offerEvent) {
493 eventQueueHandler.offered(this, event);
494 }
495 }
496
497 private void rejectTask(Runnable task) {
498 getRejectedExecutionHandler().rejectedExecution(task, this);
499 }
500
501 private void checkTaskType(Runnable task) {
502 if (!(task instanceof IoEvent)) {
503 throw new IllegalArgumentException("task must be an IoEvent or its subclass.");
504 }
505 }
506
507
508
509
510 @Override
511 public int getActiveCount() {
512 synchronized (workers) {
513 return workers.size() - idleWorkers.get();
514 }
515 }
516
517
518
519
520 @Override
521 public long getCompletedTaskCount() {
522 synchronized (workers) {
523 long answer = completedTaskCount;
524 for (Worker w : workers) {
525 answer += w.completedTaskCount;
526 }
527
528 return answer;
529 }
530 }
531
532
533
534
535 @Override
536 public int getLargestPoolSize() {
537 return largestPoolSize;
538 }
539
540
541
542
543 @Override
544 public int getPoolSize() {
545 synchronized (workers) {
546 return workers.size();
547 }
548 }
549
550
551
552
553 @Override
554 public long getTaskCount() {
555 return getCompletedTaskCount();
556 }
557
558
559
560
561 @Override
562 public boolean isTerminating() {
563 synchronized (workers) {
564 return isShutdown() && !isTerminated();
565 }
566 }
567
568
569
570
571 @Override
572 public int prestartAllCoreThreads() {
573 int answer = 0;
574 synchronized (workers) {
575 for (int i = super.getCorePoolSize() - workers.size(); i > 0; i--) {
576 addWorker();
577 answer++;
578 }
579 }
580 return answer;
581 }
582
583
584
585
586 @Override
587 public boolean prestartCoreThread() {
588 synchronized (workers) {
589 if (workers.size() < super.getCorePoolSize()) {
590 addWorker();
591 return true;
592 } else {
593 return false;
594 }
595 }
596 }
597
598
599
600
601 @Override
602 public BlockingQueue<Runnable> getQueue() {
603 throw new UnsupportedOperationException();
604 }
605
606
607
608
609 @Override
610 public void purge() {
611
612 }
613
614
615
616
617 @Override
618 public boolean remove(Runnable task) {
619 checkTaskType(task);
620 IoEvent event = (IoEvent) task;
621 IoSession session = event.getSession();
622 SessionTasksQueue sessionTasksQueue = (SessionTasksQueue) session.getAttribute(TASKS_QUEUE);
623 Queue<Runnable> tasksQueue = sessionTasksQueue.tasksQueue;
624
625 if (sessionTasksQueue == null) {
626 return false;
627 }
628
629 boolean removed;
630
631 synchronized (tasksQueue) {
632 removed = tasksQueue.remove(task);
633 }
634
635 if (removed) {
636 getQueueHandler().polled(this, event);
637 }
638
639 return removed;
640 }
641
642
643
644
645 @Override
646 public int getCorePoolSize() {
647 return super.getCorePoolSize();
648 }
649
650
651
652
653 @Override
654 public void setCorePoolSize(int corePoolSize) {
655 if (corePoolSize < 0) {
656 throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
657 }
658 if (corePoolSize > super.getMaximumPoolSize()) {
659 throw new IllegalArgumentException("corePoolSize exceeds maximumPoolSize");
660 }
661
662 synchronized (workers) {
663 if (super.getCorePoolSize() > corePoolSize) {
664 for (int i = super.getCorePoolSize() - corePoolSize; i > 0; i--) {
665 removeWorker();
666 }
667 }
668 super.setCorePoolSize(corePoolSize);
669 }
670 }
671
672 private class Worker implements Runnable {
673
674 private volatile long completedTaskCount;
675
676 private Thread thread;
677
678 public void run() {
679 thread = Thread.currentThread();
680
681 try {
682 for (;;) {
683 IoSession session = fetchSession();
684
685 idleWorkers.decrementAndGet();
686
687 if (session == null) {
688 synchronized (workers) {
689 if (workers.size() > getCorePoolSize()) {
690
691 workers.remove(this);
692 break;
693 }
694 }
695 }
696
697 if (session == EXIT_SIGNAL) {
698 break;
699 }
700
701 try {
702 if (session != null) {
703 runTasks(getSessionTasksQueue(session));
704 }
705 } finally {
706 idleWorkers.incrementAndGet();
707 }
708 }
709 } finally {
710 synchronized (workers) {
711 workers.remove(this);
712 OrderedThreadPoolExecutor.this.completedTaskCount += completedTaskCount;
713 workers.notifyAll();
714 }
715 }
716 }
717
718 private IoSession fetchSession() {
719 IoSession session = null;
720 long currentTime = System.currentTimeMillis();
721 long deadline = currentTime + getKeepAliveTime(TimeUnit.MILLISECONDS);
722 for (;;) {
723 try {
724 long waitTime = deadline - currentTime;
725 if (waitTime <= 0) {
726 break;
727 }
728
729 try {
730 session = waitingSessions.poll(waitTime, TimeUnit.MILLISECONDS);
731 break;
732 } finally {
733 if (session == null) {
734 currentTime = System.currentTimeMillis();
735 }
736 }
737 } catch (InterruptedException e) {
738
739 continue;
740 }
741 }
742 return session;
743 }
744
745 private void runTasks(SessionTasksQueue sessionTasksQueue) {
746 for (;;) {
747 Runnable task;
748 Queue<Runnable> tasksQueue = sessionTasksQueue.tasksQueue;
749
750 synchronized (tasksQueue) {
751 task = tasksQueue.poll();
752
753 if (task == null) {
754 sessionTasksQueue.processingCompleted = true;
755 break;
756 }
757 }
758
759 eventQueueHandler.polled(OrderedThreadPoolExecutor.this, (IoEvent) task);
760
761 runTask(task);
762 }
763 }
764
765 private void runTask(Runnable task) {
766 beforeExecute(thread, task);
767 boolean ran = false;
768 try {
769 task.run();
770 ran = true;
771 afterExecute(task, null);
772 completedTaskCount++;
773 } catch (RuntimeException e) {
774 if (!ran) {
775 afterExecute(task, e);
776 }
777 throw e;
778 }
779 }
780 }
781
782
783
784
785
786 private class SessionTasksQueue {
787
788 private final Queue<Runnable> tasksQueue = new ConcurrentLinkedQueue<Runnable>();
789
790
791 private boolean processingCompleted = true;
792 }
793 }