@@ -321,6 +321,8 @@ public static Scheduler single() {
321
321
* non-delayed tasks as it can, which may result in a longer than expected occupation of a
322
322
* thread of the given backing Executor. In other terms, it does not allow per-Runnable fairness
323
323
* in case the worker runs on a shared underlying thread of the Executor.
324
+ * See {@link #from(Executor, boolean, boolean)} to create a wrapper that uses the underlying Executor
325
+ * more fairly.
324
326
* <p>
325
327
* Starting, stopping and restarting this scheduler is not supported (no-op) and the provided
326
328
* executor's lifecycle must be managed externally:
@@ -346,10 +348,11 @@ public static Scheduler single() {
346
348
* @param executor
347
349
* the executor to wrap
348
350
* @return the new Scheduler wrapping the Executor
351
+ * @see #from(Executor, boolean, boolean)
349
352
*/
350
353
@ NonNull
351
354
public static Scheduler from (@ NonNull Executor executor ) {
352
- return new ExecutorScheduler (executor , false );
355
+ return new ExecutorScheduler (executor , false , false );
353
356
}
354
357
355
358
/**
@@ -382,6 +385,8 @@ public static Scheduler from(@NonNull Executor executor) {
382
385
* non-delayed tasks as it can, which may result in a longer than expected occupation of a
383
386
* thread of the given backing Executor. In other terms, it does not allow per-Runnable fairness
384
387
* in case the worker runs on a shared underlying thread of the Executor.
388
+ * See {@link #from(Executor, boolean, boolean)} to create a wrapper that uses the underlying Executor
389
+ * more fairly.
385
390
* <p>
386
391
* Starting, stopping and restarting this scheduler is not supported (no-op) and the provided
387
392
* executor's lifecycle must be managed externally:
@@ -411,10 +416,82 @@ public static Scheduler from(@NonNull Executor executor) {
411
416
* be interrupted when the task is disposed.
412
417
* @return the new Scheduler wrapping the Executor
413
418
* @since 3.0.0
419
+ * @see #from(Executor, boolean, boolean)
414
420
*/
415
421
@ NonNull
416
422
public static Scheduler from (@ NonNull Executor executor , boolean interruptibleWorker ) {
417
- return new ExecutorScheduler (executor , interruptibleWorker );
423
+ return new ExecutorScheduler (executor , interruptibleWorker , false );
424
+ }
425
+
426
+ /**
427
+ * Wraps an {@link Executor} into a new Scheduler instance and delegates {@code schedule()}
428
+ * calls to it.
429
+ * <p>
430
+ * The tasks scheduled by the returned {@link Scheduler} and its {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker}
431
+ * can be optionally interrupted.
432
+ * <p>
433
+ * If the provided executor doesn't support any of the more specific standard Java executor
434
+ * APIs, tasks scheduled with a time delay or periodically will use the
435
+ * {@link #single()} scheduler for the timed waiting
436
+ * before posting the actual task to the given executor.
437
+ * <p>
438
+ * If the provided executor supports the standard Java {@link ExecutorService} API,
439
+ * canceling tasks scheduled by this scheduler can be cancelled/interrupted by calling
440
+ * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with
441
+ * a time delay or periodically will use the {@link #single()} scheduler for the timed waiting
442
+ * before posting the actual task to the given executor.
443
+ * <p>
444
+ * If the provided executor supports the standard Java {@link ScheduledExecutorService} API,
445
+ * canceling tasks scheduled by this scheduler can be cancelled/interrupted by calling
446
+ * {@link io.reactivex.rxjava3.disposables.Disposable#dispose()}. In addition, tasks scheduled with
447
+ * a time delay or periodically will use the provided executor. Note, however, if the provided
448
+ * {@code ScheduledExecutorService} instance is not single threaded, tasks scheduled
449
+ * with a time delay close to each other may end up executing in different order than
450
+ * the original schedule() call was issued. This limitation may be lifted in a future patch.
451
+ * <p>
452
+ * The implementation of the Worker of this wrapper Scheduler can operate in both eager (non-fair) and
453
+ * fair modes depending on the specified parameter. In <em>eager</em> mode, it will execute as many
454
+ * non-delayed tasks as it can, which may result in a longer than expected occupation of a
455
+ * thread of the given backing Executor. In other terms, it does not allow per-Runnable fairness
456
+ * in case the worker runs on a shared underlying thread of the Executor. In <em>fair</em> mode,
457
+ * non-delayed tasks will still be executed in a FIFO and non-overlapping manner, but after each task,
458
+ * the execution for the next task is rescheduled with the same underlying Executor, allowing interleaving
459
+ * from both the same Scheduler or other external usages of the underlying Executor.
460
+ * <p>
461
+ * Starting, stopping and restarting this scheduler is not supported (no-op) and the provided
462
+ * executor's lifecycle must be managed externally:
463
+ * <pre><code>
464
+ * ExecutorService exec = Executors.newSingleThreadedExecutor();
465
+ * try {
466
+ * Scheduler scheduler = Schedulers.from(exec, true, true);
467
+ * Flowable.just(1)
468
+ * .subscribeOn(scheduler)
469
+ * .map(v -> v + 1)
470
+ * .observeOn(scheduler)
471
+ * .blockingSubscribe(System.out::println);
472
+ * } finally {
473
+ * exec.shutdown();
474
+ * }
475
+ * </code></pre>
476
+ * <p>
477
+ * This type of scheduler is less sensitive to leaking {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} instances, although
478
+ * not disposing a worker that has timed/delayed tasks not cancelled by other means may leak resources and/or
479
+ * execute those tasks "unexpectedly".
480
+ * <p>
481
+ * Note that this method returns a new {@link Scheduler} instance, even for the same {@link Executor} instance.
482
+ * @param executor
483
+ * the executor to wrap
484
+ * @param interruptibleWorker if {@code true} the tasks submitted to the {@link io.reactivex.rxjava3.core.Scheduler.Worker Scheduler.Worker} will
485
+ * be interrupted when the task is disposed.
486
+ * @param fair if {@code true} tasks submitted to the will be executed by the underlying {@link Executor} one after the other, still
487
+ * in a FIFO and non-overlapping manner, but allows interleaving with other tasks submitted to the underlying {@code Executor}.
488
+ * If {@code false}, the underlying FIFO scheme will execute as many tasks as it can before giving up the underlying {@code Executor} thread.
489
+ * @return the new Scheduler wrapping the Executor
490
+ * @since 3.0.0
491
+ */
492
+ @ NonNull
493
+ public static Scheduler from (@ NonNull Executor executor , boolean interruptibleWorker , boolean fair ) {
494
+ return new ExecutorScheduler (executor , interruptibleWorker , fair );
418
495
}
419
496
420
497
/**
0 commit comments