Skip to content

Commit 5da378f

Browse files
JakeWhartonakarnokd
authored andcommitted
Expose scheduler factories which accept thread factories. (#3879)
This allows hooks to create schedulers whose threads have different priorities.
1 parent 8c82440 commit 5da378f

File tree

9 files changed

+218
-40
lines changed

9 files changed

+218
-40
lines changed

src/main/java/rx/internal/schedulers/CachedThreadScheduler.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,39 +24,39 @@
2424
import rx.subscriptions.*;
2525

2626
public final class CachedThreadScheduler extends Scheduler implements SchedulerLifecycle {
27-
private static final String WORKER_THREAD_NAME_PREFIX = "RxCachedThreadScheduler-";
28-
static final RxThreadFactory WORKER_THREAD_FACTORY =
29-
new RxThreadFactory(WORKER_THREAD_NAME_PREFIX);
30-
31-
private static final String EVICTOR_THREAD_NAME_PREFIX = "RxCachedWorkerPoolEvictor-";
32-
static final RxThreadFactory EVICTOR_THREAD_FACTORY =
33-
new RxThreadFactory(EVICTOR_THREAD_NAME_PREFIX);
34-
3527
private static final long KEEP_ALIVE_TIME = 60;
3628
private static final TimeUnit KEEP_ALIVE_UNIT = TimeUnit.SECONDS;
3729

3830
static final ThreadWorker SHUTDOWN_THREADWORKER;
3931
static {
40-
SHUTDOWN_THREADWORKER = new ThreadWorker(new RxThreadFactory("RxCachedThreadSchedulerShutdown-"));
32+
SHUTDOWN_THREADWORKER = new ThreadWorker(RxThreadFactory.NONE);
4133
SHUTDOWN_THREADWORKER.unsubscribe();
4234
}
4335

4436
private static final class CachedWorkerPool {
37+
private final ThreadFactory threadFactory;
4538
private final long keepAliveTime;
4639
private final ConcurrentLinkedQueue<ThreadWorker> expiringWorkerQueue;
4740
private final CompositeSubscription allWorkers;
4841
private final ScheduledExecutorService evictorService;
4942
private final Future<?> evictorTask;
5043

51-
CachedWorkerPool(long keepAliveTime, TimeUnit unit) {
44+
CachedWorkerPool(final ThreadFactory threadFactory, long keepAliveTime, TimeUnit unit) {
45+
this.threadFactory = threadFactory;
5246
this.keepAliveTime = unit != null ? unit.toNanos(keepAliveTime) : 0L;
5347
this.expiringWorkerQueue = new ConcurrentLinkedQueue<ThreadWorker>();
5448
this.allWorkers = new CompositeSubscription();
5549

5650
ScheduledExecutorService evictor = null;
5751
Future<?> task = null;
5852
if (unit != null) {
59-
evictor = Executors.newScheduledThreadPool(1, EVICTOR_THREAD_FACTORY);
53+
evictor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
54+
@Override public Thread newThread(Runnable r) {
55+
Thread thread = threadFactory.newThread(r);
56+
thread.setName(thread.getName() + " (Evictor)");
57+
return thread;
58+
}
59+
});
6060
NewThreadWorker.tryEnableCancelPolicy(evictor);
6161
task = evictor.scheduleWithFixedDelay(
6262
new Runnable() {
@@ -83,7 +83,7 @@ ThreadWorker get() {
8383
}
8484

8585
// No cached worker found, so create a new one.
86-
ThreadWorker w = new ThreadWorker(WORKER_THREAD_FACTORY);
86+
ThreadWorker w = new ThreadWorker(threadFactory);
8787
allWorkers.add(w);
8888
return w;
8989
}
@@ -131,22 +131,25 @@ void shutdown() {
131131
}
132132
}
133133

134+
final ThreadFactory threadFactory;
134135
final AtomicReference<CachedWorkerPool> pool;
135136

136137
static final CachedWorkerPool NONE;
137138
static {
138-
NONE = new CachedWorkerPool(0, null);
139+
NONE = new CachedWorkerPool(null, 0, null);
139140
NONE.shutdown();
140141
}
141142

142-
public CachedThreadScheduler() {
143+
public CachedThreadScheduler(ThreadFactory threadFactory) {
144+
this.threadFactory = threadFactory;
143145
this.pool = new AtomicReference<CachedWorkerPool>(NONE);
144146
start();
145147
}
146148

147149
@Override
148150
public void start() {
149-
CachedWorkerPool update = new CachedWorkerPool(KEEP_ALIVE_TIME, KEEP_ALIVE_UNIT);
151+
CachedWorkerPool update =
152+
new CachedWorkerPool(threadFactory, KEEP_ALIVE_TIME, KEEP_ALIVE_UNIT);
150153
if (!pool.compareAndSet(NONE, update)) {
151154
update.shutdown();
152155
}

src/main/java/rx/internal/schedulers/EventLoopsScheduler.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
import rx.internal.util.*;
2424
import rx.subscriptions.*;
2525

26-
public class EventLoopsScheduler extends Scheduler implements SchedulerLifecycle {
27-
/** Manages a fixed number of workers. */
28-
private static final String THREAD_NAME_PREFIX = "RxComputationThreadPool-";
29-
static final RxThreadFactory THREAD_FACTORY = new RxThreadFactory(THREAD_NAME_PREFIX);
26+
public final class EventLoopsScheduler extends Scheduler implements SchedulerLifecycle {
3027
/**
3128
* Key to setting the maximum number of computation scheduler threads.
3229
* Zero or less is interpreted as use available. Capped by available.
@@ -48,7 +45,7 @@ public class EventLoopsScheduler extends Scheduler implements SchedulerLifecycle
4845

4946
static final PoolWorker SHUTDOWN_WORKER;
5047
static {
51-
SHUTDOWN_WORKER = new PoolWorker(new RxThreadFactory("RxComputationShutdown-"));
48+
SHUTDOWN_WORKER = new PoolWorker(RxThreadFactory.NONE);
5249
SHUTDOWN_WORKER.unsubscribe();
5350
}
5451

@@ -58,12 +55,12 @@ static final class FixedSchedulerPool {
5855
final PoolWorker[] eventLoops;
5956
long n;
6057

61-
FixedSchedulerPool(int maxThreads) {
58+
FixedSchedulerPool(ThreadFactory threadFactory, int maxThreads) {
6259
// initialize event loops
6360
this.cores = maxThreads;
6461
this.eventLoops = new PoolWorker[maxThreads];
6562
for (int i = 0; i < maxThreads; i++) {
66-
this.eventLoops[i] = new PoolWorker(THREAD_FACTORY);
63+
this.eventLoops[i] = new PoolWorker(threadFactory);
6764
}
6865
}
6966

@@ -83,15 +80,17 @@ public void shutdown() {
8380
}
8481
}
8582
/** This will indicate no pool is active. */
86-
static final FixedSchedulerPool NONE = new FixedSchedulerPool(0);
83+
static final FixedSchedulerPool NONE = new FixedSchedulerPool(null, 0);
8784

85+
final ThreadFactory threadFactory;
8886
final AtomicReference<FixedSchedulerPool> pool;
8987

9088
/**
9189
* Create a scheduler with pool size equal to the available processor
9290
* count and using least-recent worker selection policy.
9391
*/
94-
public EventLoopsScheduler() {
92+
public EventLoopsScheduler(ThreadFactory threadFactory) {
93+
this.threadFactory = threadFactory;
9594
this.pool = new AtomicReference<FixedSchedulerPool>(NONE);
9695
start();
9796
}
@@ -103,7 +102,7 @@ public Worker createWorker() {
103102

104103
@Override
105104
public void start() {
106-
FixedSchedulerPool update = new FixedSchedulerPool(MAX_THREADS);
105+
FixedSchedulerPool update = new FixedSchedulerPool(threadFactory, MAX_THREADS);
107106
if (!pool.compareAndSet(NONE, update)) {
108107
update.shutdown();
109108
}

src/main/java/rx/internal/schedulers/NewThreadScheduler.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,21 @@
1515
*/
1616
package rx.internal.schedulers;
1717

18+
import java.util.concurrent.ThreadFactory;
1819
import rx.Scheduler;
19-
import rx.internal.util.RxThreadFactory;
2020

2121
/**
2222
* Schedules work on a new thread.
2323
*/
2424
public final class NewThreadScheduler extends Scheduler {
25+
private final ThreadFactory threadFactory;
2526

26-
private static final String THREAD_NAME_PREFIX = "RxNewThreadScheduler-";
27-
private static final RxThreadFactory THREAD_FACTORY = new RxThreadFactory(THREAD_NAME_PREFIX);
28-
29-
public NewThreadScheduler() {
27+
public NewThreadScheduler(ThreadFactory threadFactory) {
28+
this.threadFactory = threadFactory;
3029
}
3130

3231
@Override
3332
public Worker createWorker() {
34-
return new NewThreadWorker(THREAD_FACTORY);
33+
return new NewThreadWorker(threadFactory);
3534
}
3635
}

src/main/java/rx/internal/util/RxThreadFactory.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
import java.util.concurrent.atomic.AtomicLong;
2020

2121
public final class RxThreadFactory extends AtomicLong implements ThreadFactory {
22+
public static final ThreadFactory NONE = new ThreadFactory() {
23+
@Override public Thread newThread(Runnable r) {
24+
throw new AssertionError("No threads allowed.");
25+
}
26+
};
27+
2228
final String prefix;
2329

2430
public RxThreadFactory(String prefix) {

src/main/java/rx/plugins/RxJavaSchedulersHook.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717
package rx.plugins;
1818

19+
import java.util.concurrent.ThreadFactory;
1920
import rx.Scheduler;
2021
import rx.annotations.Experimental;
2122
import rx.functions.Action0;
2223
import rx.internal.schedulers.CachedThreadScheduler;
2324
import rx.internal.schedulers.EventLoopsScheduler;
2425
import rx.internal.schedulers.NewThreadScheduler;
26+
import rx.internal.util.RxThreadFactory;
2527
import rx.schedulers.Schedulers;
2628

2729
/**
@@ -45,23 +47,53 @@ public class RxJavaSchedulersHook {
4547
*/
4648
@Experimental
4749
public static Scheduler createComputationScheduler() {
48-
return new EventLoopsScheduler();
50+
return createComputationScheduler(new RxThreadFactory("RxComputationScheduler-"));
51+
}
52+
53+
/**
54+
* Create an instance of the default {@link Scheduler} used for {@link Schedulers#computation()}
55+
* except using {@code threadFactory} for thread creation.
56+
*/
57+
@Experimental
58+
public static Scheduler createComputationScheduler(ThreadFactory threadFactory) {
59+
if (threadFactory == null) throw new NullPointerException("threadFactory == null");
60+
return new EventLoopsScheduler(threadFactory);
4961
}
5062

5163
/**
5264
* Create an instance of the default {@link Scheduler} used for {@link Schedulers#io()}.
5365
*/
5466
@Experimental
5567
public static Scheduler createIoScheduler() {
56-
return new CachedThreadScheduler();
68+
return createIoScheduler(new RxThreadFactory("RxIoScheduler-"));
69+
}
70+
71+
/**
72+
* Create an instance of the default {@link Scheduler} used for {@link Schedulers#io()}
73+
* except using {@code threadFactory} for thread creation.
74+
*/
75+
@Experimental
76+
public static Scheduler createIoScheduler(ThreadFactory threadFactory) {
77+
if (threadFactory == null) throw new NullPointerException("threadFactory == null");
78+
return new CachedThreadScheduler(threadFactory);
5779
}
5880

5981
/**
6082
* Create an instance of the default {@link Scheduler} used for {@link Schedulers#newThread()}.
6183
*/
6284
@Experimental
6385
public static Scheduler createNewThreadScheduler() {
64-
return new NewThreadScheduler();
86+
return createNewThreadScheduler(new RxThreadFactory("RxNewThreadScheduler-"));
87+
}
88+
89+
/**
90+
* Create an instance of the default {@link Scheduler} used for {@link Schedulers#newThread()}
91+
* except using {@code threadFactory} for thread creation.
92+
*/
93+
@Experimental
94+
public static Scheduler createNewThreadScheduler(ThreadFactory threadFactory) {
95+
if (threadFactory == null) throw new NullPointerException("threadFactory == null");
96+
return new NewThreadScheduler(threadFactory);
6597
}
6698

6799
protected RxJavaSchedulersHook() {

src/test/java/rx/internal/operators/OperatorObserveOnTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public void call(Integer t1) {
238238
* Confirm that running on a ThreadPoolScheduler allows multiple threads but is still ordered.
239239
*/
240240
@Test
241-
public void testObserveOnWithThreadPoolScheduler() {
241+
public void testObserveOnWithComputationScheduler() {
242242
final AtomicInteger count = new AtomicInteger();
243243
final int _multiple = 99;
244244

@@ -255,7 +255,7 @@ public Integer call(Integer t1) {
255255
@Override
256256
public void call(Integer t1) {
257257
assertEquals(count.incrementAndGet() * _multiple, t1.intValue());
258-
assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool"));
258+
assertTrue(Thread.currentThread().getName().startsWith("RxComputationScheduler"));
259259
}
260260

261261
});
@@ -295,7 +295,7 @@ public Integer call(Integer t1) {
295295
@Override
296296
public void call(Integer t1) {
297297
assertEquals(count.incrementAndGet() * _multiple, t1.intValue());
298-
assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool"));
298+
assertTrue(Thread.currentThread().getName().startsWith("RxComputationScheduler"));
299299
}
300300

301301
});

0 commit comments

Comments
 (0)