3131 * the work asynchronously on the appropriate {@link Scheduler} implementation. This means for example that you would not use this approach
3232 * along with {@link TrampolineScheduler} or {@link ImmediateScheduler}.
3333 */
34- public final class GenericScheduledExecutorService implements SchedulerLifecycle {
34+ public final class GenericScheduledExecutorService implements SchedulerLifecycle {
3535
3636 private static final String THREAD_NAME_PREFIX = "RxScheduledExecutorPool-" ;
3737 private static final RxThreadFactory THREAD_FACTORY = new RxThreadFactory (THREAD_NAME_PREFIX );
3838
39- private static final ScheduledExecutorService NONE ;
39+ private static final ScheduledExecutorService [] NONE = new ScheduledExecutorService [0 ];
40+
41+ private static final ScheduledExecutorService SHUTDOWN ;
4042 static {
41- NONE = Executors .newScheduledThreadPool (0 );
42- NONE . shutdownNow ();
43+ SHUTDOWN = Executors .newScheduledThreadPool (0 );
44+ SHUTDOWN . shutdown ();
4345 }
4446
4547 /* Schedulers needs acces to this in order to work with the lifecycle. */
4648 public final static GenericScheduledExecutorService INSTANCE = new GenericScheduledExecutorService ();
4749
48- private final AtomicReference <ScheduledExecutorService > executor ;
50+ private final AtomicReference <ScheduledExecutorService [] > executor ;
4951
52+ /** We don't use atomics with this because thread-assignment is random anyway. */
53+ private static int roundRobin ;
54+
5055 private GenericScheduledExecutorService () {
51- executor = new AtomicReference <ScheduledExecutorService >(NONE );
56+ executor = new AtomicReference <ScheduledExecutorService [] >(NONE );
5257 start ();
5358 }
5459
@@ -63,39 +68,60 @@ public void start() {
6368 count = 8 ;
6469 }
6570
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+ }
7184 }
7285 }
7386 } else {
74- exec .shutdownNow ();
87+ for (ScheduledExecutorService exec : execs ) {
88+ exec .shutdownNow ();
89+ }
7590 }
7691 }
7792
7893 @ Override
7994 public void shutdown () {
8095 for (;;) {
81- ScheduledExecutorService exec = executor .get ();
82- if (exec == NONE ) {
96+ ScheduledExecutorService [] execs = executor .get ();
97+ if (execs == NONE ) {
8398 return ;
8499 }
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+ }
88105 return ;
89106 }
90107 }
91108 }
92109
93110 /**
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 .
95112 *
96113 * @return {@link ScheduledExecutorService} for generic use.
97114 */
98115 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 ];
100126 }
101127}
0 commit comments