31
31
* the work asynchronously on the appropriate {@link Scheduler} implementation. This means for example that you would not use this approach
32
32
* along with {@link TrampolineScheduler} or {@link ImmediateScheduler}.
33
33
*/
34
- public final class GenericScheduledExecutorService implements SchedulerLifecycle {
34
+ public final class GenericScheduledExecutorService implements SchedulerLifecycle {
35
35
36
36
private static final String THREAD_NAME_PREFIX = "RxScheduledExecutorPool-" ;
37
37
private static final RxThreadFactory THREAD_FACTORY = new RxThreadFactory (THREAD_NAME_PREFIX );
38
38
39
- private static final ScheduledExecutorService NONE ;
39
+ private static final ScheduledExecutorService [] NONE = new ScheduledExecutorService [0 ];
40
+
41
+ private static final ScheduledExecutorService SHUTDOWN ;
40
42
static {
41
- NONE = Executors .newScheduledThreadPool (0 );
42
- NONE . shutdownNow ();
43
+ SHUTDOWN = Executors .newScheduledThreadPool (0 );
44
+ SHUTDOWN . shutdown ();
43
45
}
44
46
45
47
/* Schedulers needs acces to this in order to work with the lifecycle. */
46
48
public final static GenericScheduledExecutorService INSTANCE = new GenericScheduledExecutorService ();
47
49
48
- private final AtomicReference <ScheduledExecutorService > executor ;
50
+ private final AtomicReference <ScheduledExecutorService [] > executor ;
49
51
52
+ /** We don't use atomics with this because thread-assignment is random anyway. */
53
+ private static int roundRobin ;
54
+
50
55
private GenericScheduledExecutorService () {
51
- executor = new AtomicReference <ScheduledExecutorService >(NONE );
56
+ executor = new AtomicReference <ScheduledExecutorService [] >(NONE );
52
57
start ();
53
58
}
54
59
@@ -63,39 +68,60 @@ public void start() {
63
68
count = 8 ;
64
69
}
65
70
66
- ScheduledExecutorService exec = Executors .newScheduledThreadPool (count , THREAD_FACTORY );
67
- if (executor .compareAndSet (NONE , exec )) {
68
- if (!NewThreadWorker .tryEnableCancelPolicy (exec )) {
69
- if (exec instanceof ScheduledThreadPoolExecutor ) {
70
- NewThreadWorker .registerExecutor ((ScheduledThreadPoolExecutor )exec );
71
+ // A multi-threaded executor can reorder tasks, having a set of them
72
+ // and handing one of those out on getInstance() ensures a proper order
73
+
74
+ ScheduledExecutorService [] execs = new ScheduledExecutorService [count ];
75
+ for (int i = 0 ; i < count ; i ++) {
76
+ execs [i ] = Executors .newScheduledThreadPool (1 , THREAD_FACTORY );
77
+ }
78
+ if (executor .compareAndSet (NONE , execs )) {
79
+ for (ScheduledExecutorService exec : execs ) {
80
+ if (!NewThreadWorker .tryEnableCancelPolicy (exec )) {
81
+ if (exec instanceof ScheduledThreadPoolExecutor ) {
82
+ NewThreadWorker .registerExecutor ((ScheduledThreadPoolExecutor )exec );
83
+ }
71
84
}
72
85
}
73
86
} else {
74
- exec .shutdownNow ();
87
+ for (ScheduledExecutorService exec : execs ) {
88
+ exec .shutdownNow ();
89
+ }
75
90
}
76
91
}
77
92
78
93
@ Override
79
94
public void shutdown () {
80
95
for (;;) {
81
- ScheduledExecutorService exec = executor .get ();
82
- if (exec == NONE ) {
96
+ ScheduledExecutorService [] execs = executor .get ();
97
+ if (execs == NONE ) {
83
98
return ;
84
99
}
85
- if (executor .compareAndSet (exec , NONE )) {
86
- NewThreadWorker .deregisterExecutor (exec );
87
- exec .shutdownNow ();
100
+ if (executor .compareAndSet (execs , NONE )) {
101
+ for (ScheduledExecutorService exec : execs ) {
102
+ NewThreadWorker .deregisterExecutor (exec );
103
+ exec .shutdownNow ();
104
+ }
88
105
return ;
89
106
}
90
107
}
91
108
}
92
109
93
110
/**
94
- * See class Javadoc for information on what this is for and how to use .
111
+ * Returns one of the single-threaded ScheduledExecutorService helper executors .
95
112
*
96
113
* @return {@link ScheduledExecutorService} for generic use.
97
114
*/
98
115
public static ScheduledExecutorService getInstance () {
99
- return INSTANCE .executor .get ();
116
+ ScheduledExecutorService [] execs = INSTANCE .executor .get ();
117
+ if (execs == NONE ) {
118
+ return SHUTDOWN ;
119
+ }
120
+ int r = roundRobin + 1 ;
121
+ if (r >= execs .length ) {
122
+ r = 0 ;
123
+ }
124
+ roundRobin = r ;
125
+ return execs [r ];
100
126
}
101
127
}
0 commit comments