diff --git a/src/main/java/io/reactivex/rxjava4/annotations/SchedulerSupport.java b/src/main/java/io/reactivex/rxjava4/annotations/SchedulerSupport.java index 9ddcdea883..2a07964427 100644 --- a/src/main/java/io/reactivex/rxjava4/annotations/SchedulerSupport.java +++ b/src/main/java/io/reactivex/rxjava4/annotations/SchedulerSupport.java @@ -46,10 +46,24 @@ */ String COMPUTATION = "io.reactivex:computation"; /** - * The operator/class runs on RxJava's {@linkplain Schedulers#io() I/O scheduler} or takes + * The operator/class runs on RxJava's {@linkplain Schedulers#cached() I/O scheduler} or takes * timing information from it. + * @deprecated since 4.0.0, use the more specific {@link #CACHED} or {@link #VIRTUAL} constants */ + @Deprecated(since = "4.0.0") String IO = "io.reactivex:io"; + /** + * The operator/class runs on RxJava's {@linkplain Schedulers#cached() I/O scheduler} or takes + * timing information from it. + * @since 4.0.0 + */ + String CACHED = "io.reactivex:cached"; + /** + * The operator/class runs on RxJava's {@linkplain Schedulers#virtual() Virtual scheduler} or takes + * timing information from it. + * @since 4.0.0 + */ + String VIRTUAL = "io.reactivex:virtual"; /** * The operator/class runs on RxJava's {@linkplain Schedulers#newThread() new thread scheduler} * or takes timing information from it. diff --git a/src/main/java/io/reactivex/rxjava4/core/Completable.java b/src/main/java/io/reactivex/rxjava4/core/Completable.java index b0a68a7696..58b6645152 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Completable.java +++ b/src/main/java/io/reactivex/rxjava4/core/Completable.java @@ -69,7 +69,7 @@ * Example: *

  * Disposable d = Completable.complete()
- *    .delay(10, TimeUnit.SECONDS, Schedulers.io())
+ *    .delay(10, TimeUnit.SECONDS, Schedulers.cached())
  *    .subscribeWith(new DisposableCompletableObserver() {
  *        @Override
  *        public void onStart() {
diff --git a/src/main/java/io/reactivex/rxjava4/core/Flowable.java b/src/main/java/io/reactivex/rxjava4/core/Flowable.java
index db007192d3..ea3758f9c1 100644
--- a/src/main/java/io/reactivex/rxjava4/core/Flowable.java
+++ b/src/main/java/io/reactivex/rxjava4/core/Flowable.java
@@ -51,7 +51,7 @@
  * Reactive Streams implementations.
  * 

* The {@code Flowable} hosts the default buffer size of 128 elements for operators, accessible via {@link #bufferSize()}, - * that can be overridden globally via the system parameter {@code rx3.buffer-size}. Most operators, however, have + * that can be overridden globally via the system parameter {@code rx4.buffer-size}. Most operators, however, have * overloads that allow setting their internal buffer size explicitly. *

* The documentation for this class makes use of marble diagrams. The following legend explains these diagrams: @@ -161,7 +161,7 @@ public abstract non-sealed class Flowable<@NonNull T> implements Publisher, /** The default buffer size. */ static final int BUFFER_SIZE; static { - BUFFER_SIZE = Math.max(1, Integer.getInteger("rx3.buffer-size", 128)); + BUFFER_SIZE = Math.max(1, Integer.getInteger("rx4.buffer-size", 128)); } /** @@ -250,7 +250,7 @@ public abstract non-sealed class Flowable<@NonNull T> implements Publisher, /** * Returns the default internal buffer size used by most async operators. - *

The value can be overridden via system parameter {@code rx3.buffer-size} + *

The value can be overridden via system parameter {@code rx4.buffer-size} * before the {@code Flowable} class is loaded. * @return the default internal buffer size. */ @@ -20815,7 +20815,100 @@ public final Stream blockingStream(int prefetch) { public static <@NonNull T> Flowable virtualCreate(@NonNull VirtualGenerator generator, @NonNull ExecutorService executor) { Objects.requireNonNull(generator, "generator is null"); Objects.requireNonNull(executor, "executor is null"); - return RxJavaPlugins.onAssembly(new FlowableVirtualCreateExecutor<>(generator, executor)); + return RxJavaPlugins.onAssembly(new FlowableVirtualCreateExecutor<>(generator, executor, null)); + } + + /** + * Construct a {@code Flowable} and use the given {@code generator} + * to generate items on demand while running on the {@link Schedulers#virtual()}. + *

+ *

+ *
Backpressure:
+ *
This operator honors backpressure from downstream and blocks the emitter if + * the downstream is not ready. + *
+ *
Scheduler:
+ *
The operator by default runs on the {@link Schedulers#virtual()} scheduler.
+ *
+ *

+ * Note that backpressure is handled via blocking so it is recommended the default + * {@link Scheduler} uses virtual threads, such as the one returned by + * {@link Schedulers#virtual()}. + *

+ * Examples: + *


+     *     Flowable.<Integer>virtualCreate(emitter -> {
+     *         for (int i = 0; i < 10; i++) {
+     *             Thread.sleep(1000);
+     *             emitter.emit(i);
+     *         }
+     *     })
+     *     .subscribe(
+     *         System.out::println,
+     *         Throwable::printStackTrace,
+     *         () -> System.out.println("Done")
+     *     );
+     * 
+ * @param the element type to emit + * @param generator the callback used to generate items on demand by the downstream + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code generator} or {@code executor} is {@code null} + * @since 4.0.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.VIRTUAL) + @NonNull + public static <@NonNull T> Flowable virtualCreate(@NonNull VirtualGenerator generator) { + return virtualCreate(generator, Schedulers.virtual()); + } + + /** + * Construct a {@code Flowable} and use the given {@code generator} + * to generate items on demand while running on the given {@link Scheduler}. + *

+ *

+ *
Backpressure:
+ *
This operator honors backpressure from downstream and blocks the emitter if + * the downstream is not ready. + *
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ *

+ * Note that backpressure is handled via blocking so it is recommended the provided + * {@code Scheduler} uses virtual threads, such as the one returned by + * {@link Executors#newVirtualThreadPerTaskExecutor()}. + *

+ * Examples: + *


+     *     Flowable.<Integer>virtualCreate(emitter -> {
+     *         for (int i = 0; i < 10; i++) {
+     *             Thread.sleep(1000);
+     *             emitter.emit(i);
+     *         }
+     *     }, Schedulers.virtual())
+     *     .subscribe(
+     *         System.out::println,
+     *         Throwable::printStackTrace,
+     *         () -> System.out.println("Done")
+     *     );
+     * 
+ * @param the element type to emit + * @param generator the callback used to generate items on demand by the downstream + * @param scheduler the target {@code Scheduler} to use for running the callback + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code generator} or {@code scheduler} is {@code null} + * @since 4.0.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + public static <@NonNull T> Flowable virtualCreate(@NonNull VirtualGenerator generator, @NonNull Scheduler scheduler) { + Objects.requireNonNull(generator, "generator is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + return RxJavaPlugins.onAssembly(new FlowableVirtualCreateExecutor<>(generator, null, scheduler)); } /** @@ -20835,7 +20928,8 @@ public final Stream blockingStream(int prefetch) { * {@code ExecutorService} uses virtual threads, such as the one returned by * {@link Executors#newVirtualThreadPerTaskExecutor()}. * @param the downstream element type - * @param transformer the callback whose {@link VirtualTransformer#transform(Object, VirtualEmitter)} is invoked for each upstream item + * @param transformer the callback whose {@link VirtualTransformer#transform(Object, VirtualEmitter)} + * is invoked for each upstream item * @param executor the target {@code ExecutorService} to use for running the callback * @return the new {@code Flowable} instance * @throws NullPointerException if {@code transformer} or {@code executor} is {@code null} @@ -20845,10 +20939,80 @@ public final Stream blockingStream(int prefetch) { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull R> Flowable virtualTransform(@NonNull VirtualTransformer transformer, @NonNull ExecutorService executor) { + public final <@NonNull R> Flowable virtualTransform(@NonNull VirtualTransformer transformer, + @NonNull ExecutorService executor) { return virtualTransform(transformer, executor, Flowable.bufferSize()); } + /** + * Returns a {@code Flowable} that turns an upstream item an upstream item into + * zero or more downstream values by running on the {@link Schedulers#virtual()} scheduler. + *

+ *

+ *
Backpressure:
+ *
This operator honors backpressure from downstream and blocks the emitter if + * the downstream is not ready. + *
+ *
Scheduler:
+ *
The operator by default runs on the {@link Schedulers#virtual()} scheduler.
+ *
+ *

+ * Note that backpressure is handled via blocking so it is recommended the default + * {@link Scheduler} uses virtual threads, such as the one returned by + * {@link Executors#newVirtualThreadPerTaskExecutor()}. + * @param the downstream element type + * @param transformer the callback whose {@link VirtualTransformer#transform(Object, VirtualEmitter)} + * is invoked for each upstream item + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code transformer} is {@code null} + * @since 4.0.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.VIRTUAL) + @NonNull + public final <@NonNull R> Flowable virtualTransform(@NonNull VirtualTransformer transformer) { + return virtualTransform(transformer, Schedulers.virtual(), Flowable.bufferSize()); + } + + /** + * Returns a {@code Flowable} that turns an upstream item an upstream item into + * zero or more downstream values by running on the given {@link Scheduler}. + *

+ *

+ *
Backpressure:
+ *
This operator honors backpressure from downstream and blocks the emitter if + * the downstream is not ready. + *
+ *
Scheduler:
+ *
You specify which {@code Scheduler} this operator will use.
+ *
+ *

+ * Note that backpressure is handled via blocking so it is recommended the provided + * {@code Scheduler} uses virtual threads, such as the one returned by + * {@link Schedulers#virtual()}. + * @param the downstream element type + * @param transformer the callback whose {@link VirtualTransformer#transform(Object, VirtualEmitter)} + * is invoked for each upstream item + * @param scheduler the target {@code Scheduler} to use for running the callback + * @param prefetch the number of items to fetch from the upstream. + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code transformer} or {@code scheduler} is {@code null} + * @throws IllegalArgumentException if {@code prefetch} is non-positive + * @since 4.0.0 + */ + @CheckReturnValue + @BackpressureSupport(BackpressureKind.FULL) + @SchedulerSupport(SchedulerSupport.CUSTOM) + @NonNull + public final <@NonNull R> Flowable virtualTransform(@NonNull VirtualTransformer transformer, + @NonNull Scheduler scheduler, int prefetch) { + Objects.requireNonNull(transformer, "transformer is null"); + Objects.requireNonNull(scheduler, "scheduler is null"); + ObjectHelper.verifyPositive(prefetch, "prefetch"); + return new FlowableVirtualTransformExecutor<>(this, transformer, null, scheduler, prefetch); + } + /** * Returns a {@code Flowable} that turns an upstream item into zero or more downstream * values by running on the given {@link ExecutorService}. @@ -20866,7 +21030,8 @@ public final Stream blockingStream(int prefetch) { * {@code ExecutorService} uses virtual threads, such as the one returned by * {@link Executors#newVirtualThreadPerTaskExecutor()}. * @param the downstream element type - * @param transformer the callback whose {@link VirtualTransformer#transform(Object, VirtualEmitter)} is invoked for each upstream item + * @param transformer the callback whose {@link VirtualTransformer#transform(Object, VirtualEmitter)} + * is invoked for each upstream item * @param executor the target {@code ExecutorService} to use for running the callback * @param prefetch the number of items to fetch from the upstream. * @return the new {@code Flowable} instance @@ -20878,11 +21043,12 @@ public final Stream blockingStream(int prefetch) { @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull R> Flowable virtualTransform(@NonNull VirtualTransformer transformer, @NonNull ExecutorService executor, int prefetch) { + public final <@NonNull R> Flowable virtualTransform(@NonNull VirtualTransformer transformer, + @NonNull ExecutorService executor, int prefetch) { Objects.requireNonNull(transformer, "transformer is null"); Objects.requireNonNull(executor, "executor is null"); ObjectHelper.verifyPositive(prefetch, "prefetch"); - return new FlowableVirtualTransformExecutor<>(this, transformer, executor, prefetch); + return new FlowableVirtualTransformExecutor<>(this, transformer, executor, null, prefetch); } } diff --git a/src/main/java/io/reactivex/rxjava4/core/Maybe.java b/src/main/java/io/reactivex/rxjava4/core/Maybe.java index 8b14019411..a040c2a8e8 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Maybe.java +++ b/src/main/java/io/reactivex/rxjava4/core/Maybe.java @@ -68,7 +68,7 @@ * Example: *


  * Disposable d = Maybe.just("Hello World")
- *    .delay(10, TimeUnit.SECONDS, Schedulers.io())
+ *    .delay(10, TimeUnit.SECONDS, Schedulers.cached())
  *    .subscribeWith(new DisposableMaybeObserver<String>() {
  *        @Override
  *        public void onStart() {
diff --git a/src/main/java/io/reactivex/rxjava4/core/Observable.java b/src/main/java/io/reactivex/rxjava4/core/Observable.java
index 4cfa9094b7..c68130859d 100644
--- a/src/main/java/io/reactivex/rxjava4/core/Observable.java
+++ b/src/main/java/io/reactivex/rxjava4/core/Observable.java
@@ -47,7 +47,7 @@
  * for such non-backpressured flows, which {@code Observable} itself implements as well.
  * 

* The {@code Observable}'s operators, by default, run with a buffer size of 128 elements (see {@link Flowable#bufferSize()}), - * that can be overridden globally via the system parameter {@code rx3.buffer-size}. Most operators, however, have + * that can be overridden globally via the system parameter {@code rx4.buffer-size}. Most operators, however, have * overloads that allow setting their internal buffer size explicitly. *

* The documentation for this class makes use of marble diagrams. The following legend explains these diagrams: @@ -181,7 +181,7 @@ public abstract class Observable<@NonNull T> implements ObservableSource { /** * Returns the default 'island' size or capacity-increment hint for unbounded buffers. *

Delegates to {@link Flowable#bufferSize} but is public for convenience. - *

The value can be overridden via system parameter {@code rx3.buffer-size} + *

The value can be overridden via system parameter {@code rx4.buffer-size} * before the {@link Flowable} class is loaded. * @return the default 'island' size or capacity-increment hint */ diff --git a/src/main/java/io/reactivex/rxjava4/core/Scheduler.java b/src/main/java/io/reactivex/rxjava4/core/Scheduler.java index fc500b374c..8a4ead7afb 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Scheduler.java +++ b/src/main/java/io/reactivex/rxjava4/core/Scheduler.java @@ -62,7 +62,7 @@ * can detect the earlier hook and not apply a new one over again. *

* The default implementation of {@link #now(TimeUnit)} and {@link Worker#now(TimeUnit)} methods to return current {@link System#currentTimeMillis()} - * value in the desired time unit, unless {@code rx3.scheduler.use-nanotime} (boolean) is set. When the property is set to + * value in the desired time unit, unless {@code rx4.scheduler.use-nanotime} (boolean) is set. When the property is set to * {@code true}, the method uses {@link System#nanoTime()} as its basis instead. Custom {@code Scheduler} implementations can override this * to provide specialized time accounting (such as virtual time to be advanced programmatically). * Note that operators requiring a {@code Scheduler} may rely on either of the {@code now()} calls provided by @@ -75,7 +75,7 @@ * based on the relative time between it and {@link Worker#now(TimeUnit)}. However, drifts or changes in the * system clock could affect this calculation either by scheduling subsequent runs too frequently or too far apart. * Therefore, the default implementation uses the {@link #clockDriftTolerance()} value (set via - * {@code rx3.scheduler.drift-tolerance} and {@code rx3.scheduler.drift-tolerance-unit}) to detect a + * {@code rx4.scheduler.drift-tolerance} and {@code rx4.scheduler.drift-tolerance-unit}) to detect a * drift in {@link Worker#now(TimeUnit)} and re-adjust the absolute/relative time calculation accordingly. *

* The default implementations of {@link #start()} and {@link #shutdown()} do nothing and should be overridden if the @@ -96,10 +96,10 @@ public abstract class Scheduler { *

* Associated system parameter: *

    - *
  • {@code rx3.scheduler.use-nanotime}, boolean, default {@code false} + *
  • {@code rx4.scheduler.use-nanotime}, boolean, default {@code false} *
*/ - static boolean IS_DRIFT_USE_NANOTIME = Boolean.getBoolean("rx3.scheduler.use-nanotime"); + static boolean IS_DRIFT_USE_NANOTIME = Boolean.getBoolean("rx4.scheduler.use-nanotime"); /** * Returns the current clock time depending on state of {@link Scheduler#IS_DRIFT_USE_NANOTIME} in given {@code unit} @@ -123,15 +123,15 @@ static long computeNow(TimeUnit unit) { *

* Associated system parameters: *

    - *
  • {@code rx3.scheduler.drift-tolerance}, long, default {@code 15}
  • - *
  • {@code rx3.scheduler.drift-tolerance-unit}, string, default {@code minutes}, + *
  • {@code rx4.scheduler.drift-tolerance}, long, default {@code 15}
  • + *
  • {@code rx4.scheduler.drift-tolerance-unit}, string, default {@code minutes}, * supports {@code seconds} and {@code milliseconds}. *
*/ static final long CLOCK_DRIFT_TOLERANCE_NANOSECONDS = computeClockDrift( - Long.getLong("rx3.scheduler.drift-tolerance", 15), - System.getProperty("rx3.scheduler.drift-tolerance-unit", "minutes") + Long.getLong("rx4.scheduler.drift-tolerance", 15), + System.getProperty("rx4.scheduler.drift-tolerance-unit", "minutes") ); /** @@ -153,8 +153,8 @@ static long computeClockDrift(long time, String timeUnit) { * Returns the clock drift tolerance in nanoseconds. *

Related system properties: *

    - *
  • {@code rx3.scheduler.drift-tolerance}, long, default {@code 15}
  • - *
  • {@code rx3.scheduler.drift-tolerance-unit}, string, default {@code minutes}, + *
  • {@code rx4.scheduler.drift-tolerance}, long, default {@code 15}
  • + *
  • {@code rx4.scheduler.drift-tolerance-unit}, string, default {@code minutes}, * supports {@code seconds} and {@code milliseconds}. *
* @return the tolerance in nanoseconds @@ -393,7 +393,7 @@ public S when(@NonNull Function * The default implementation of the {@link #now(TimeUnit)} method returns current {@link System#currentTimeMillis()} - * value in the desired time unit, unless {@code rx3.scheduler.use-nanotime} (boolean) is set. When the property is set to + * value in the desired time unit, unless {@code rx4.scheduler.use-nanotime} (boolean) is set. When the property is set to * {@code true}, the method uses {@link System#nanoTime()} as its basis instead. Custom {@code Worker} implementations can override this * to provide specialized time accounting (such as virtual time to be advanced programmatically). * Note that operators requiring a scheduler may rely on either of the {@code now()} calls provided by @@ -406,7 +406,7 @@ public S when(@NonNull Function * If the {@code Worker} is disposed, the {@code schedule} methods diff --git a/src/main/java/io/reactivex/rxjava4/core/Single.java b/src/main/java/io/reactivex/rxjava4/core/Single.java index 06516c2ff2..00c8ecfcba 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Single.java +++ b/src/main/java/io/reactivex/rxjava4/core/Single.java @@ -76,7 +76,7 @@ * Example: *

  * Disposable d = Single.just("Hello World")
- *    .delay(10, TimeUnit.SECONDS, Schedulers.io())
+ *    .delay(10, TimeUnit.SECONDS, Schedulers.cached())
  *    .subscribeWith(new DisposableSingleObserver<String>() {
  *        @Override
  *        public void onStart() {
diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/IoScheduler.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/CachedScheduler.java
similarity index 94%
rename from src/main/java/io/reactivex/rxjava4/internal/schedulers/IoScheduler.java
rename to src/main/java/io/reactivex/rxjava4/internal/schedulers/CachedScheduler.java
index 36a877d482..60ece46d8a 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/schedulers/IoScheduler.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/CachedScheduler.java
@@ -24,7 +24,7 @@
 /**
  * Scheduler that creates and caches a set of thread pools and reuses them if possible.
  */
-public final class IoScheduler extends Scheduler {
+public final class CachedScheduler extends Scheduler {
     private static final String WORKER_THREAD_NAME_PREFIX = "RxCachedThreadScheduler";
     static final RxThreadFactory WORKER_THREAD_FACTORY;
 
@@ -32,7 +32,7 @@ public final class IoScheduler extends Scheduler {
     static final RxThreadFactory EVICTOR_THREAD_FACTORY;
 
     /** The name of the system property for setting the keep-alive time (in seconds) for this Scheduler workers. */
-    private static final String KEY_KEEP_ALIVE_TIME = "rx3.io-keep-alive-time";
+    private static final String KEY_KEEP_ALIVE_TIME = "rx4.cached-keep-alive-time";
     public static final long KEEP_ALIVE_TIME_DEFAULT = 60;
 
     private static final long KEEP_ALIVE_TIME;
@@ -43,10 +43,10 @@ public final class IoScheduler extends Scheduler {
     final AtomicReference pool;
 
     /** The name of the system property for setting the thread priority for this Scheduler. */
-    private static final String KEY_IO_PRIORITY = "rx3.io-priority";
+    private static final String KEY_IO_PRIORITY = "rx4.cached-priority";
 
     /** The name of the system property for setting the release behaviour for this Scheduler. */
-    private static final String KEY_SCHEDULED_RELEASE = "rx3.io-scheduled-release";
+    private static final String KEY_SCHEDULED_RELEASE = "rx4.cached-scheduled-release";
     static boolean USE_SCHEDULED_RELEASE;
 
     static final CachedWorkerPool NONE;
@@ -156,16 +156,16 @@ void shutdown() {
         }
     }
 
-    public IoScheduler() {
+    public CachedScheduler() {
         this(WORKER_THREAD_FACTORY);
     }
 
     /**
-     * Constructs an IoScheduler with the given thread factory and starts the pool of workers.
+     * Constructs an CachedScheduler with the given thread factory and starts the pool of workers.
      * @param threadFactory thread factory to use for creating worker threads. Note that this takes precedence over any
      *                      system properties for configuring new thread creation. Cannot be null.
      */
-    public IoScheduler(ThreadFactory threadFactory) {
+    public CachedScheduler(ThreadFactory threadFactory) {
         this.threadFactory = threadFactory;
         this.pool = new AtomicReference<>(NONE);
         start();
diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/ComputationScheduler.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/ComputationScheduler.java
index 701317dbc3..533e31f6b6 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/schedulers/ComputationScheduler.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/ComputationScheduler.java
@@ -36,7 +36,7 @@ public final class ComputationScheduler extends Scheduler implements SchedulerMu
      * Key to setting the maximum number of computation scheduler threads.
      * Zero or less is interpreted as use available. Capped by available.
      */
-    static final String KEY_MAX_THREADS = "rx3.computation-threads";
+    static final String KEY_MAX_THREADS = "rx4.computation-threads";
     /** The maximum number of computation scheduler threads. */
     static final int MAX_THREADS;
 
@@ -45,7 +45,7 @@ public final class ComputationScheduler extends Scheduler implements SchedulerMu
     final ThreadFactory threadFactory;
     final AtomicReference pool;
     /** The name of the system property for setting the thread priority for this Scheduler. */
-    private static final String KEY_COMPUTATION_PRIORITY = "rx3.computation-priority";
+    private static final String KEY_COMPUTATION_PRIORITY = "rx4.computation-priority";
 
     static {
         MAX_THREADS = cap(Runtime.getRuntime().availableProcessors(), Integer.getInteger(KEY_MAX_THREADS, 0));
diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/DeferredExecutorScheduler.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/DeferredExecutorScheduler.java
new file mode 100644
index 0000000000..632c032401
--- /dev/null
+++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/DeferredExecutorScheduler.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2016-present, RxJava Contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License.
+ */
+
+package io.reactivex.rxjava4.internal.schedulers;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import io.reactivex.rxjava4.annotations.NonNull;
+import io.reactivex.rxjava4.core.Scheduler;
+import io.reactivex.rxjava4.disposables.*;
+import io.reactivex.rxjava4.exceptions.Exceptions;
+import io.reactivex.rxjava4.functions.Supplier;
+import io.reactivex.rxjava4.internal.disposables.*;
+import io.reactivex.rxjava4.internal.functions.Functions;
+import io.reactivex.rxjava4.internal.queue.MpscLinkedQueue;
+import io.reactivex.rxjava4.plugins.RxJavaPlugins;
+import io.reactivex.rxjava4.schedulers.*;
+
+/**
+ * Wraps an Executor supplier and provides the Scheduler API over an instance of Executor
+ * created on demand.
+ */
+public final class DeferredExecutorScheduler extends Scheduler {
+
+    final boolean interruptibleWorker;
+
+    final boolean fair;
+
+    @NonNull
+    final Supplier executorSupplier;
+
+    static final class SingleHolder {
+        static final Scheduler HELPER = Schedulers.single();
+    }
+
+    public DeferredExecutorScheduler(@NonNull Supplier executorSupplier, boolean interruptibleWorker, boolean fair) {
+        this.executorSupplier = executorSupplier;
+        this.interruptibleWorker = interruptibleWorker;
+        this.fair = fair;
+    }
+
+    @NonNull
+    @Override
+    public Worker createWorker() {
+        try {
+            return new ExecutorWorker(executorSupplier.get(), interruptibleWorker, fair);
+        } catch (Throwable t) {
+            Exceptions.throwIfFatal(t);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    /* public: test support. */
+    public static final class ExecutorWorker extends Scheduler.Worker implements Runnable {
+
+        final boolean interruptibleWorker;
+
+        final boolean fair;
+
+        final Executor executor;
+
+        final MpscLinkedQueue queue;
+
+        volatile boolean disposed;
+
+        final AtomicInteger wip = new AtomicInteger();
+
+        final CompositeDisposable tasks = new CompositeDisposable();
+
+        public ExecutorWorker(Executor executor, boolean interruptibleWorker, boolean fair) {
+            this.executor = executor;
+            this.queue = new MpscLinkedQueue<>();
+            this.interruptibleWorker = interruptibleWorker;
+            this.fair = fair;
+        }
+
+        @NonNull
+        @Override
+        public Disposable schedule(@NonNull Runnable run) {
+            if (disposed) {
+                return EmptyDisposable.INSTANCE;
+            }
+
+            Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
+
+            Runnable task;
+            Disposable disposable;
+
+            if (interruptibleWorker) {
+                InterruptibleRunnable interruptibleTask = new InterruptibleRunnable(decoratedRun, tasks);
+                tasks.add(interruptibleTask);
+
+                task = interruptibleTask;
+                disposable = interruptibleTask;
+            } else {
+                @SuppressWarnings("resource")
+                BooleanRunnable runnableTask = new BooleanRunnable(decoratedRun);
+
+                task = runnableTask;
+                disposable = runnableTask;
+            }
+
+            queue.offer(task);
+
+            if (wip.getAndIncrement() == 0) {
+                try {
+                    executor.execute(this);
+                } catch (RejectedExecutionException ex) {
+                    disposed = true;
+                    queue.clear();
+                    RxJavaPlugins.onError(ex);
+                    return EmptyDisposable.INSTANCE;
+                }
+            }
+
+            return disposable;
+        }
+
+        @NonNull
+        @Override
+        public Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
+            if (delay <= 0) {
+                return schedule(run);
+            }
+            if (disposed) {
+                return EmptyDisposable.INSTANCE;
+            }
+
+            SequentialDisposable first = new SequentialDisposable();
+
+            final SequentialDisposable mar = new SequentialDisposable(first);
+
+            final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
+
+            ScheduledRunnable sr = new ScheduledRunnable(new SequentialDispose(mar, decoratedRun), tasks, interruptibleWorker);
+            tasks.add(sr);
+
+            if (executor instanceof ScheduledExecutorService) {
+                try {
+                    Future f = ((ScheduledExecutorService)executor).schedule((Callable)sr, delay, unit);
+                    sr.setFuture(f);
+                } catch (RejectedExecutionException ex) {
+                    disposed = true;
+                    RxJavaPlugins.onError(ex);
+                    return EmptyDisposable.INSTANCE;
+                }
+            } else {
+                final Disposable d = SingleHolder.HELPER.scheduleDirect(sr, delay, unit);
+                sr.setFuture(new DisposeOnCancel(d));
+            }
+
+            first.replace(sr);
+
+            return mar;
+        }
+
+        @Override
+        public void dispose() {
+            if (!disposed) {
+                disposed = true;
+                try {
+                    tasks.dispose();
+                    if (wip.getAndIncrement() == 0) {
+                        queue.clear();
+                    }
+                } finally {
+                    if (executor instanceof ExecutorService exec) {
+                        exec.shutdown();
+                    }
+                }
+            }
+        }
+
+        @Override
+        public boolean isDisposed() {
+            return disposed;
+        }
+
+        @Override
+        public void run() {
+            if (fair) {
+                runFair();
+            } else {
+                runEager();
+            }
+        }
+
+        void runFair() {
+            final MpscLinkedQueue q = queue;
+            if (disposed) {
+                q.clear();
+                return;
+            }
+
+            Runnable run = q.poll();
+            run.run(); // never null because of offer + increment happens first
+
+            if (disposed) {
+                q.clear();
+                return;
+            }
+
+            if (wip.decrementAndGet() != 0) {
+                executor.execute(this);
+            }
+        }
+
+        void runEager() {
+            int missed = 1;
+            final MpscLinkedQueue q = queue;
+            for (;;) {
+
+                if (disposed) {
+                    q.clear();
+                    return;
+                }
+
+                for (;;) {
+                    Runnable run = q.poll();
+                    if (run == null) {
+                        break;
+                    }
+                    run.run();
+
+                    if (disposed) {
+                        q.clear();
+                        return;
+                    }
+                }
+
+                if (disposed) {
+                    q.clear();
+                    return;
+                }
+
+                missed = wip.addAndGet(-missed);
+                if (missed == 0) {
+                    break;
+                }
+            }
+        }
+
+        static final class BooleanRunnable extends AtomicBoolean implements Runnable, Disposable {
+
+            private static final long serialVersionUID = -2421395018820541164L;
+
+            final Runnable actual;
+            BooleanRunnable(Runnable actual) {
+                this.actual = actual;
+            }
+
+            @Override
+            public void run() {
+                if (get()) {
+                    return;
+                }
+                try {
+                    actual.run();
+                } catch (Throwable ex) {
+                    // Exceptions.throwIfFatal(ex); nowhere to go
+                    RxJavaPlugins.onError(ex);
+                    throw ex;
+                } finally {
+                    lazySet(true);
+                }
+            }
+
+            @Override
+            public void dispose() {
+                lazySet(true);
+            }
+
+            @Override
+            public boolean isDisposed() {
+                return get();
+            }
+        }
+
+        final class SequentialDispose implements Runnable {
+            private final SequentialDisposable mar;
+            private final Runnable decoratedRun;
+
+            SequentialDispose(SequentialDisposable mar, Runnable decoratedRun) {
+                this.mar = mar;
+                this.decoratedRun = decoratedRun;
+            }
+
+            @Override
+            public void run() {
+                mar.replace(schedule(decoratedRun));
+            }
+        }
+
+        /**
+         * Wrapper for a {@link Runnable} with additional logic for handling interruption on
+         * a shared thread, similar to how Java Executors do it.
+         */
+        static final class InterruptibleRunnable extends AtomicInteger implements Runnable, Disposable {
+
+            private static final long serialVersionUID = -3603436687413320876L;
+
+            final Runnable run;
+
+            final DisposableContainer tasks;
+
+            volatile Thread thread;
+
+            static final int READY = 0;
+
+            static final int RUNNING = 1;
+
+            static final int FINISHED = 2;
+
+            static final int INTERRUPTING = 3;
+
+            static final int INTERRUPTED = 4;
+
+            InterruptibleRunnable(Runnable run, DisposableContainer tasks) {
+                this.run = run;
+                this.tasks = tasks;
+            }
+
+            @Override
+            public void run() {
+                if (get() == READY) {
+                    thread = Thread.currentThread();
+                    if (compareAndSet(READY, RUNNING)) {
+                        try {
+                            try {
+                                run.run();
+                            } catch (Throwable ex) {
+                                // Exceptions.throwIfFatal(ex); nowhere to go
+                                RxJavaPlugins.onError(ex);
+                                throw ex;
+                            }
+                        } finally {
+                            thread = null;
+                            if (compareAndSet(RUNNING, FINISHED)) {
+                                cleanup();
+                            } else {
+                                while (get() == INTERRUPTING) {
+                                    Thread.yield();
+                                }
+                                Thread.interrupted();
+                            }
+                        }
+                    } else {
+                        thread = null;
+                    }
+                }
+            }
+
+            @Override
+            public void dispose() {
+                for (;;) {
+                    int state = get();
+                    if (state >= FINISHED) {
+                        break;
+                    } else if (state == READY) {
+                        if (compareAndSet(READY, INTERRUPTED)) {
+                            cleanup();
+                            break;
+                        }
+                    } else {
+                        if (compareAndSet(RUNNING, INTERRUPTING)) {
+                            Thread t = thread;
+                            if (t != null) {
+                                t.interrupt();
+                                thread = null;
+                            }
+                            set(INTERRUPTED);
+                            cleanup();
+                            break;
+                        }
+                    }
+                }
+            }
+
+            void cleanup() {
+                if (tasks != null) {
+                    tasks.delete(this);
+                }
+            }
+
+            @Override
+            public boolean isDisposed() {
+                return get() >= FINISHED;
+            }
+        }
+    }
+
+    static final class DelayedRunnable extends AtomicReference
+            implements Runnable, Disposable, SchedulerRunnableIntrospection {
+
+        private static final long serialVersionUID = -4101336210206799084L;
+
+        final SequentialDisposable timed;
+
+        final SequentialDisposable direct;
+
+        DelayedRunnable(Runnable run) {
+            super(run);
+            this.timed = new SequentialDisposable();
+            this.direct = new SequentialDisposable();
+        }
+
+        @Override
+        public void run() {
+            Runnable r = get();
+            if (r != null) {
+                try {
+                    try {
+                        r.run();
+                    } finally {
+                        lazySet(null);
+                        timed.lazySet(DisposableHelper.DISPOSED);
+                        direct.lazySet(DisposableHelper.DISPOSED);
+                    }
+                } catch (Throwable ex) {
+                    // Exceptions.throwIfFatal(ex); nowhere to go
+                    RxJavaPlugins.onError(ex);
+                    throw ex;
+                }
+            }
+        }
+
+        @Override
+        public boolean isDisposed() {
+            return get() == null;
+        }
+
+        @Override
+        public void dispose() {
+            if (getAndSet(null) != null) {
+                timed.dispose();
+                direct.dispose();
+            }
+        }
+
+        @Override
+        public Runnable getWrappedRunnable() {
+            Runnable r = get();
+            return r != null ? r : Functions.EMPTY_RUNNABLE;
+        }
+    }
+
+    final class DelayedDispose implements Runnable {
+        private final DelayedRunnable dr;
+
+        DelayedDispose(DelayedRunnable dr) {
+            this.dr = dr;
+        }
+
+        @Override
+        public void run() {
+            dr.direct.replace(scheduleDirect(dr));
+        }
+    }
+}
diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/NewThreadScheduler.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/NewThreadScheduler.java
index cabd52f34c..6eea82b769 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/schedulers/NewThreadScheduler.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/NewThreadScheduler.java
@@ -29,7 +29,7 @@ public final class NewThreadScheduler extends Scheduler {
     private static final RxThreadFactory THREAD_FACTORY;
 
     /** The name of the system property for setting the thread priority for this Scheduler. */
-    private static final String KEY_NEWTHREAD_PRIORITY = "rx3.newthread-priority";
+    private static final String KEY_NEWTHREAD_PRIORITY = "rx4.newthread-priority";
 
     static {
         int priority = Math.max(Thread.MIN_PRIORITY, Math.min(Thread.MAX_PRIORITY,
diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/SchedulerPoolFactory.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/SchedulerPoolFactory.java
index 056a6283a3..a8507aa1e8 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/schedulers/SchedulerPoolFactory.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/SchedulerPoolFactory.java
@@ -27,7 +27,7 @@ private SchedulerPoolFactory() {
         throw new IllegalStateException("No instances!");
     }
 
-    static final String PURGE_ENABLED_KEY = "rx3.purge-enabled";
+    static final String PURGE_ENABLED_KEY = "rx4.purge-enabled";
 
     public static final boolean PURGE_ENABLED;
 
diff --git a/src/main/java/io/reactivex/rxjava4/internal/schedulers/SingleScheduler.java b/src/main/java/io/reactivex/rxjava4/internal/schedulers/SingleScheduler.java
index 82650ddf2b..a762fe1c37 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/schedulers/SingleScheduler.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/schedulers/SingleScheduler.java
@@ -32,7 +32,7 @@ public final class SingleScheduler extends Scheduler {
     final AtomicReference executor = new AtomicReference<>();
 
     /** The name of the system property for setting the thread priority for this Scheduler. */
-    private static final String KEY_SINGLE_PRIORITY = "rx3.single-priority";
+    private static final String KEY_SINGLE_PRIORITY = "rx4.single-priority";
 
     private static final String THREAD_NAME_PREFIX = "RxSingleScheduler";
 
diff --git a/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualCreateExecutor.java b/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualCreateExecutor.java
index f15b0ba9ad..c619e6b14a 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualCreateExecutor.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualCreateExecutor.java
@@ -35,9 +35,12 @@ public final class FlowableVirtualCreateExecutor extends Flowable {
 
     final ExecutorService executor;
 
-    public FlowableVirtualCreateExecutor(VirtualGenerator generator, ExecutorService executor) {
+    final Scheduler scheduler;
+
+    public FlowableVirtualCreateExecutor(VirtualGenerator generator, ExecutorService executor, Scheduler scheduler) {
         this.generator = generator;
         this.executor = executor;
+        this.scheduler = scheduler;
     }
 
     @Override
@@ -45,11 +48,17 @@ protected void subscribeActual(Subscriber s) {
         var parent = new ExecutorVirtualCreateSubscription<>(s, generator);
         s.onSubscribe(parent);
 
-        executor.submit(parent);
+        if (executor != null) {
+            executor.submit((Callable)parent);
+        } else {
+            var worker = scheduler.createWorker();
+            parent.worker = worker;
+            worker.schedule(parent);
+        }
     }
 
     static final class ExecutorVirtualCreateSubscription extends AtomicLong
-    implements Subscription, Callable, VirtualEmitter {
+    implements Subscription, Callable, Runnable, VirtualEmitter {
 
         private static final long serialVersionUID = -6959205135542203083L;
 
@@ -65,12 +74,19 @@ static final class ExecutorVirtualCreateSubscription extends AtomicLong
 
         long produced;
 
+        Scheduler.Worker worker;
+
         ExecutorVirtualCreateSubscription(Subscriber downstream, VirtualGenerator generator) {
             this.downstream = downstream;
             this.generator = generator;
             this.consumerReady = new VirtualResumable();
         }
 
+        @Override
+        public void run() {
+            call();
+        }
+
         @Override
         public Void call() {
             try {
@@ -88,6 +104,11 @@ public Void call() {
                 }
             } finally {
                 downstream = null;
+                var w = worker;
+                worker = null;
+                if (w != null) {
+                    w.close();
+                }
             }
             return null;
         }
diff --git a/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualTransformExecutor.java b/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualTransformExecutor.java
index 6dd34d6b73..806e072f22 100644
--- a/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualTransformExecutor.java
+++ b/src/main/java/io/reactivex/rxjava4/internal/virtual/FlowableVirtualTransformExecutor.java
@@ -19,6 +19,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import io.reactivex.rxjava4.core.*;
+import io.reactivex.rxjava4.core.Scheduler.Worker;
 import io.reactivex.rxjava4.exceptions.Exceptions;
 import io.reactivex.rxjava4.internal.util.BackpressureHelper;
 import io.reactivex.rxjava4.operators.SpscArrayQueue;
@@ -31,13 +32,19 @@ public final class FlowableVirtualTransformExecutor extends Flowable {
 
     final ExecutorService executor;
 
+    final Scheduler scheduler;
+
     final int prefetch;
 
     public FlowableVirtualTransformExecutor(Flowable source,
-            VirtualTransformer transformer, ExecutorService executor, int prefetch) {
+            VirtualTransformer transformer,
+            ExecutorService executor,
+            Scheduler scheduler,
+            int prefetch) {
         this.source = source;
         this.transformer = transformer;
         this.executor = executor;
+        this.scheduler = scheduler;
         this.prefetch = prefetch;
     }
 
@@ -45,11 +52,17 @@ public FlowableVirtualTransformExecutor(Flowable source,
     protected void subscribeActual(Subscriber s) {
         var parent = new ExecutorVirtualTransformSubscriber<>(s, transformer, prefetch);
         source.subscribe(parent);
-        executor.submit(parent);
+        if (executor != null) {
+            executor.submit((Callable)parent);
+        } else {
+            var worker = scheduler.createWorker();
+            parent.worker = worker;
+            worker.schedule(parent);
+        }
     }
 
     static final class ExecutorVirtualTransformSubscriber extends AtomicLong
-    implements FlowableSubscriber, Subscription, VirtualEmitter, Callable {
+    implements FlowableSubscriber, Subscription, VirtualEmitter, Callable, Runnable {
 
         private static final long serialVersionUID = -4702456711290258571L;
 
@@ -78,6 +91,8 @@ static final class ExecutorVirtualTransformSubscriber extends AtomicLong
 
         long produced;
 
+        Worker worker;
+
         ExecutorVirtualTransformSubscriber(Subscriber downstream,
                 VirtualTransformer transformer,
                 int prefetch) {
@@ -149,10 +164,21 @@ public void cancel() {
             upstream.cancel();
             // cleanup(); don't kill the worker
 
+            var w = worker;
+            worker = null;
+            if (w != null) {
+                w.close();
+            }
+
             producerReady.resume();
             consumerReady.resume();
         }
 
+        @Override
+        public void run() {
+            call();
+        }
+
         @Override
         public Void call() {
             try {
diff --git a/src/main/java/io/reactivex/rxjava4/plugins/RxJavaPlugins.java b/src/main/java/io/reactivex/rxjava4/plugins/RxJavaPlugins.java
index 51755fc43f..794f105430 100644
--- a/src/main/java/io/reactivex/rxjava4/plugins/RxJavaPlugins.java
+++ b/src/main/java/io/reactivex/rxjava4/plugins/RxJavaPlugins.java
@@ -45,7 +45,10 @@ public final class RxJavaPlugins {
     static volatile Function, ? extends Scheduler> onInitSingleHandler;
 
     @Nullable
-    static volatile Function, ? extends Scheduler> onInitIoHandler;
+    static volatile Function, ? extends Scheduler> onInitCachedHandler;
+
+    @Nullable
+    static volatile Function, ? extends Scheduler> onInitVirtualHandler;
 
     @Nullable
     static volatile Function, ? extends Scheduler> onInitNewThreadHandler;
@@ -57,7 +60,10 @@ public final class RxJavaPlugins {
     static volatile Function onSingleHandler;
 
     @Nullable
-    static volatile Function onIoHandler;
+    static volatile Function onCachedHandler;
+
+    @Nullable
+    static volatile Function onVirtualHandler;
 
     @Nullable
     static volatile Function onNewThreadHandler;
@@ -204,8 +210,17 @@ public static Consumer getErrorHandler() {
      * @return the hook function, may be null
      */
     @Nullable
-    public static Function, ? extends Scheduler> getInitIoSchedulerHandler() {
-        return onInitIoHandler;
+    public static Function, ? extends Scheduler> getInitCachedSchedulerHandler() {
+        return onInitCachedHandler;
+    }
+
+    /**
+     * Returns the current hook function.
+     * @return the hook function, may be null
+     */
+    @Nullable
+    public static Function, ? extends Scheduler> getInitVirtualSchedulerHandler() {
+        return onInitVirtualHandler;
     }
 
     /**
@@ -231,8 +246,17 @@ public static Consumer getErrorHandler() {
      * @return the hook function, may be null
      */
     @Nullable
-    public static Function getIoSchedulerHandler() {
-        return onIoHandler;
+    public static Function getCachedSchedulerHandler() {
+        return onCachedHandler;
+    }
+
+    /**
+     * Returns the current hook function.
+     * @return the hook function, may be null
+     */
+    @Nullable
+    public static Function getVirtualSchedulerHandler() {
+        return onVirtualHandler;
     }
 
     /**
@@ -285,9 +309,25 @@ public static Scheduler initComputationScheduler(@NonNull Supplier de
      * @throws NullPointerException if the supplier parameter or its result are null
      */
     @NonNull
-    public static Scheduler initIoScheduler(@NonNull Supplier defaultScheduler) {
+    public static Scheduler initCachedScheduler(@NonNull Supplier defaultScheduler) {
         Objects.requireNonNull(defaultScheduler, "Scheduler Supplier can't be null");
-        Function, ? extends Scheduler> f = onInitIoHandler;
+        Function, ? extends Scheduler> f = onInitCachedHandler;
+        if (f == null) {
+            return callRequireNonNull(defaultScheduler);
+        }
+        return applyRequireNonNull(f, defaultScheduler);
+    }
+
+    /**
+     * Calls the associated hook function.
+     * @param defaultScheduler a {@link Supplier} which returns the hook's input value
+     * @return the value returned by the hook, not null
+     * @throws NullPointerException if the supplier parameter or its result are null
+     */
+    @NonNull
+    public static Scheduler initVirtualScheduler(@NonNull Supplier defaultScheduler) {
+        Objects.requireNonNull(defaultScheduler, "Scheduler Supplier can't be null");
+        Function, ? extends Scheduler> f = onInitVirtualHandler;
         if (f == null) {
             return callRequireNonNull(defaultScheduler);
         }
@@ -442,8 +482,22 @@ static void uncaught(@NonNull Throwable error) {
      * @return the value returned by the hook
      */
     @NonNull
-    public static Scheduler onIoScheduler(@NonNull Scheduler defaultScheduler) {
-        Function f = onIoHandler;
+    public static Scheduler onCachedScheduler(@NonNull Scheduler defaultScheduler) {
+        Function f = onCachedHandler;
+        if (f == null) {
+            return defaultScheduler;
+        }
+        return apply(f, defaultScheduler);
+    }
+
+    /**
+     * Calls the associated hook function.
+     * @param defaultScheduler the hook's input value
+     * @return the value returned by the hook
+     */
+    @NonNull
+    public static Scheduler onVirtualScheduler(@NonNull Scheduler defaultScheduler) {
+        Function f = onVirtualHandler;
         if (f == null) {
             return defaultScheduler;
         }
@@ -504,8 +558,11 @@ public static void reset() {
         setComputationSchedulerHandler(null);
         setInitComputationSchedulerHandler(null);
 
-        setIoSchedulerHandler(null);
-        setInitIoSchedulerHandler(null);
+        setCachedSchedulerHandler(null);
+        setInitCachedSchedulerHandler(null);
+
+        setVirtualSchedulerHandler(null);
+        setInitVirtualSchedulerHandler(null);
 
         setSingleSchedulerHandler(null);
         setInitSingleSchedulerHandler(null);
@@ -575,11 +632,22 @@ public static void setInitComputationSchedulerHandler(@Nullable Function, ? extends Scheduler> handler) {
+    public static void setInitCachedSchedulerHandler(@Nullable Function, ? extends Scheduler> handler) {
+        if (lockdown) {
+            throw new IllegalStateException("Plugins can't be changed anymore");
+        }
+        onInitCachedHandler = handler;
+    }
+
+    /**
+     * Sets the specific hook function.
+     * @param handler the hook function to set, null allowed, but the function may not return null
+     */
+    public static void setInitVirtualSchedulerHandler(@Nullable Function, ? extends Scheduler> handler) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
-        onInitIoHandler = handler;
+        onInitVirtualHandler = handler;
     }
 
     /**
@@ -608,11 +676,22 @@ public static void setInitSingleSchedulerHandler(@Nullable Function handler) {
+    public static void setCachedSchedulerHandler(@Nullable Function handler) {
         if (lockdown) {
             throw new IllegalStateException("Plugins can't be changed anymore");
         }
-        onIoHandler = handler;
+        onCachedHandler = handler;
+    }
+
+    /**
+     * Sets the specific hook function.
+     * @param handler the hook function to set, null allowed
+     */
+    public static void setVirtualSchedulerHandler(@Nullable Function handler) {
+        if (lockdown) {
+            throw new IllegalStateException("Plugins can't be changed anymore");
+        }
+        onVirtualHandler = handler;
     }
 
     /**
@@ -1264,17 +1343,17 @@ public static Scheduler createComputationScheduler(@NonNull ThreadFactory thread
     }
 
     /**
-     * Create an instance of the default {@link Scheduler} used for {@link Schedulers#io()}
+     * Create an instance of the default {@link Scheduler} used for {@link Schedulers#cached()}
      * except using {@code threadFactory} for thread creation.
      * 

History: 2.0.5 - experimental * @param threadFactory thread factory to use for creating worker threads. Note that this takes precedence over any * system properties for configuring new thread creation. Cannot be null. * @return the created Scheduler instance - * @since 2.1 + * @since 4.0.0 */ @NonNull - public static Scheduler createIoScheduler(@NonNull ThreadFactory threadFactory) { - return new IoScheduler(Objects.requireNonNull(threadFactory, "threadFactory is null")); + public static Scheduler createCachedScheduler(@NonNull ThreadFactory threadFactory) { + return new CachedScheduler(Objects.requireNonNull(threadFactory, "threadFactory is null")); } /** @@ -1325,6 +1404,26 @@ public static Scheduler createExecutorScheduler(@NonNull Executor executor, bool return new ExecutorScheduler(executor, interruptibleWorker, fair); } + /** + * Create an instance of a {@link Scheduler} by wrapping a supplier of a {@link Executor}. + *

+ * This method allows creating a deferred {@code Executor}-backed {@code Scheduler} before the {@link Schedulers} class + * would initialize the standard {@code Scheduler}s. + * + * @param executorSupplier the {@code Executor} supplier to wrap and turn into a {@code Scheduler}. + * @param interruptibleWorker if {@code true}, the tasks submitted to the {@link io.reactivex.rxjava4.core.Scheduler.Worker Scheduler.Worker} will + * be interrupted when the task is disposed. + * @param fair if {@code true}, tasks submitted to the {@code Scheduler} or {@code Worker} will be executed by the underlying {@code Executor} one after the other, still + * in a FIFO and non-overlapping manner, but allows interleaving with other tasks submitted to the underlying {@code Executor}. + * If {@code false}, the underlying FIFO scheme will execute as many tasks as it can before giving up the underlying {@code Executor} thread. + * @return the new {@code Scheduler} wrapping the {@code Executor} + * @since 4.0.0 + */ + @NonNull + public static Scheduler createDeferredExecutorScheduler(@NonNull Supplier executorSupplier, boolean interruptibleWorker, boolean fair) { + return new DeferredExecutorScheduler(executorSupplier, interruptibleWorker, fair); + } + /** * Wraps the call to the function in try-catch and propagates thrown * checked exceptions as RuntimeException. diff --git a/src/main/java/io/reactivex/rxjava4/schedulers/Schedulers.java b/src/main/java/io/reactivex/rxjava4/schedulers/Schedulers.java index 6dfa308790..ce4c0dcc19 100644 --- a/src/main/java/io/reactivex/rxjava4/schedulers/Schedulers.java +++ b/src/main/java/io/reactivex/rxjava4/schedulers/Schedulers.java @@ -32,17 +32,17 @@ *

* Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.io-keep-alive-time} (long): sets the keep-alive time of the {@link #io()} {@code Scheduler} workers, - * default is {@link IoScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • - *
  • {@code rx3.io-priority} (int): sets the thread priority of the {@link #io()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.io-scheduled-release} (boolean): {@code true} sets the worker release mode of the + *
  • {@code rx4.cached-keep-alive-time} (long): sets the keep-alive time of the {@link #io()} {@code Scheduler} workers, + * default is {@link CachedScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • + *
  • {@code rx4.cached-priority} (int): sets the thread priority of the {@link #io()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx4.cached-scheduled-release} (boolean): {@code true} sets the worker release mode of the * {@link #io()} {@code Scheduler} to scheduled, default is {@code false} for eager mode.
  • - *
  • {@code rx3.computation-threads} (int): sets the number of threads in the {@link #computation()} {@code Scheduler}, default is the number of available CPUs
  • - *
  • {@code rx3.computation-priority} (int): sets the thread priority of the {@link #computation()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.newthread-priority} (int): sets the thread priority of the {@link #newThread()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.single-priority} (int): sets the thread priority of the {@link #single()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.purge-enabled} (boolean): enables purging of all {@code Scheduler}'s backing thread pools, default is {@code true}
  • - *
  • {@code rx3.scheduler.use-nanotime} (boolean): {@code true} instructs {@code Scheduler} to use {@link System#nanoTime()} for {@link Scheduler#now(TimeUnit)}, + *
  • {@code rx4.computation-threads} (int): sets the number of threads in the {@link #computation()} {@code Scheduler}, default is the number of available CPUs
  • + *
  • {@code rx4.computation-priority} (int): sets the thread priority of the {@link #computation()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx4.newthread-priority} (int): sets the thread priority of the {@link #newThread()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx4.single-priority} (int): sets the thread priority of the {@link #single()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx4.purge-enabled} (boolean): enables purging of all {@code Scheduler}'s backing thread pools, default is {@code true}
  • + *
  • {@code rx4.scheduler.use-nanotime} (boolean): {@code true} instructs {@code Scheduler} to use {@link System#nanoTime()} for {@link Scheduler#now(TimeUnit)}, * instead of default {@link System#currentTimeMillis()} ({@code false})
  • *
*/ @@ -54,7 +54,10 @@ public final class Schedulers { static final Scheduler COMPUTATION; @NonNull - static final Scheduler IO; + static final Scheduler CACHED; + + @NonNull + static final Scheduler VIRTUAL; @NonNull static final Scheduler TRAMPOLINE; @@ -71,7 +74,11 @@ static final class ComputationHolder { } static final class IoHolder { - static final Scheduler DEFAULT = new IoScheduler(); + static final Scheduler DEFAULT = new CachedScheduler(); + } + + static final class VirtualHolder { + static final Scheduler DEFAULT = new DeferredExecutorScheduler(() -> Executors.newVirtualThreadPerTaskExecutor(), true, true); } static final class NewThreadHolder { @@ -83,7 +90,9 @@ static final class NewThreadHolder { COMPUTATION = RxJavaPlugins.initComputationScheduler(new ComputationTask()); - IO = RxJavaPlugins.initIoScheduler(new IOTask()); + CACHED = RxJavaPlugins.initCachedScheduler(new IOTask()); + + VIRTUAL = RxJavaPlugins.initVirtualScheduler(new VirtualTask()); TRAMPOLINE = TrampolineScheduler.instance(); @@ -118,8 +127,8 @@ private Schedulers() { * before the {@code Schedulers} class is referenced in your code. *

Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.computation-threads} (int): sets the number of threads in the {@code computation()} {@code Scheduler}, default is the number of available CPUs
  • - *
  • {@code rx3.computation-priority} (int): sets the thread priority of the {@code computation()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx4.computation-threads} (int): sets the number of threads in the {@code computation()} {@code Scheduler}, default is the number of available CPUs
  • + *
  • {@code rx4.computation-priority} (int): sets the thread priority of the {@code computation()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • *
*

* The default value of this scheduler can be overridden at initialization time via the @@ -143,6 +152,17 @@ public static Scheduler computation() { return RxJavaPlugins.onComputationScheduler(COMPUTATION); } + /** + * Delegates to {@link Schedulers#cached()} scheduler for compatibility; please stop using this. + * @return a {@link Scheduler} meant for classical blocking IO-bound work + * @deprecated Since 4.0.0; Use a more specific {@link #cached()} or {@link #virtual()} schedulers instead. + */ + @NonNull + @Deprecated(since = "4.0.0") + public static Scheduler io() { + return cached(); + } + /** * Returns a default, shared {@link Scheduler} instance intended for IO-bound work. *

@@ -163,26 +183,27 @@ public static Scheduler computation() { * before the {@code Schedulers} class is referenced in your code. *

Supported system properties ({@code System.getProperty()}): *

    - *
  • {@code rx3.io-keep-alive-time} (long): sets the keep-alive time of the {@code io()} {@code Scheduler} workers, - * default is {@link IoScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • - *
  • {@code rx3.io-priority} (int): sets the thread priority of the {@code io()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • - *
  • {@code rx3.io-scheduled-release} (boolean): {@code true} sets the worker release mode of the + *
  • {@code rx4.cached-keep-alive-time} (long): sets the keep-alive time of the {@code io()} {@code Scheduler} workers, + * default is {@link CachedScheduler#KEEP_ALIVE_TIME_DEFAULT}
  • + *
  • {@code rx4.cached-priority} (int): sets the thread priority of the {@code io()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
  • + *
  • {@code rx4.cached-scheduled-release} (boolean): {@code true} sets the worker release mode of the * {@code #io()} {@code Scheduler} to scheduled, default is {@code false} for eager mode.
  • *
*

* The default value of this scheduler can be overridden at initialization time via the - * {@link RxJavaPlugins#setInitIoSchedulerHandler(io.reactivex.rxjava4.functions.Function)} plugin method. + * {@link RxJavaPlugins#setInitCachedSchedulerHandler(io.reactivex.rxjava4.functions.Function)} plugin method. * Note that due to possible initialization cycles, using any of the other scheduler-returning methods will * result in a {@link NullPointerException}. * Once the {@code Schedulers} class has been initialized, you can override the returned {@code Scheduler} instance - * via the {@link RxJavaPlugins#setIoSchedulerHandler(io.reactivex.rxjava4.functions.Function)} method. + * via the {@link RxJavaPlugins#setCachedSchedulerHandler(io.reactivex.rxjava4.functions.Function)} method. *

* It is possible to create a fresh instance of this scheduler with a custom {@link ThreadFactory}, via the - * {@link RxJavaPlugins#createIoScheduler(ThreadFactory)} method. Note that such custom + * {@link RxJavaPlugins#createCachedScheduler(ThreadFactory)} method. Note that such custom * instances require a manual call to {@link Scheduler#shutdown()} to allow the JVM to exit or the * (J2EE) container to unload properly. *

Operators on the base reactive classes that use this scheduler are marked with the - * @{@link io.reactivex.rxjava4.annotations.SchedulerSupport SchedulerSupport}({@link io.reactivex.rxjava4.annotations.SchedulerSupport#IO IO}) + * @{@link io.reactivex.rxjava4.annotations.SchedulerSupport SchedulerSupport} + * ({@link io.reactivex.rxjava4.annotations.SchedulerSupport#CACHED CACHED}) * annotation. *

* When the {@link io.reactivex.rxjava4.core.Scheduler.Worker Scheduler.Worker} is disposed, @@ -193,7 +214,7 @@ public static Scheduler computation() { * respond to interruption in time or at all, this may lead to delays or deadlock with the reuse use of the * underlying worker. * - *

  • In scheduled mode (enabled via the system parameter {@code rx3.io-scheduled-release} + *
  • In scheduled mode (enabled via the system parameter {@code rx4.cached-scheduled-release} * set to {@code true}), the underlying worker is returned to the cached worker pool only after the currently running task * has finished. This can help prevent premature reuse of the underlying worker and likely won't lead to delays or * deadlock with such reuses. The drawback is that the delay in release may lead to an excess amount of underlying @@ -201,10 +222,23 @@ public static Scheduler computation() { *
  • * * @return a {@code Scheduler} meant for IO-bound work + * @since 4.0.0 */ @NonNull - public static Scheduler io() { - return RxJavaPlugins.onIoScheduler(IO); + public static Scheduler cached() { + return RxJavaPlugins.onCachedScheduler(CACHED); + } + + /** + * Returns a default, shared {@link Scheduler} instance intended for virtual-blocking, including many IO-style work + * via a {@link Executors#newVirtualThreadPerTaskExecutor()} per Worker. + * TODO explain all the rest + * @return a {@code Scheduler} meant for IO-bound work + * @since 4.0.0 + */ + @NonNull + public static Scheduler virtual() { + return RxJavaPlugins.onVirtualScheduler(VIRTUAL); } /** @@ -241,7 +275,7 @@ public static Scheduler trampoline() { * before the {@code Schedulers} class is referenced in your code. *

    Supported system properties ({@code System.getProperty()}): *

      - *
    • {@code rx3.newthread-priority} (int): sets the thread priority of the {@code newThread()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
    • + *
    • {@code rx4.newthread-priority} (int): sets the thread priority of the {@code newThread()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
    • *
    *

    * The default value of this scheduler can be overridden at initialization time via the @@ -290,7 +324,7 @@ public static Scheduler newThread() { * before the {@code Schedulers} class is referenced in your code. *

    Supported system properties ({@code System.getProperty()}): *

      - *
    • {@code rx3.single-priority} (int): sets the thread priority of the {@code single()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
    • + *
    • {@code rx4.single-priority} (int): sets the thread priority of the {@code single()} {@code Scheduler}, default is {@link Thread#NORM_PRIORITY}
    • *
    *

    * The default value of this scheduler can be overridden at initialization time via the @@ -562,6 +596,21 @@ public static Scheduler from(@NonNull Executor executor, boolean interruptibleWo return RxJavaPlugins.createExecutorScheduler(executor, interruptibleWorker, fair); } + /** + * Wraps a supplier of {@link Executor} so that each worker can obtain an individual {@code Executor} instance. + * @param executorSupplier the {@link Supplier} that produces {@code Executor}s when a worker is invoked. + * @param interruptibleWorker if {@code true}, the tasks submitted to the {@link io.reactivex.rxjava4.core.Scheduler.Worker Scheduler.Worker} will + * be interrupted when the task is disposed. + * @param fair if {@code true}, tasks submitted to the {@link Scheduler} or {@code Worker} will be executed by the underlying {@code Executor} one after the other, still + * in a FIFO and non-overlapping manner, but allows interleaving with other tasks submitted to the underlying {@code Executor}. + * If {@code false}, the underlying FIFO scheme will execute as many tasks as it can before giving up the underlying {@code Executor} thread. + * @return the new {@code Scheduler} wrapping the {@code Executor} supplier + */ + @NonNull + public static Scheduler fromSupplier(@NonNull Supplier executorSupplier, boolean interruptibleWorker, boolean fair) { + return RxJavaPlugins.createDeferredExecutorScheduler(executorSupplier, interruptibleWorker, fair); + } + /** * Shuts down the standard {@link Scheduler}s. *

    The operation is idempotent and thread-safe. @@ -586,6 +635,13 @@ public static void start() { trampoline().start(); } + static final class VirtualTask implements Supplier { + @Override + public Scheduler get() { + return VirtualHolder.DEFAULT; + } + } + static final class IOTask implements Supplier { @Override public Scheduler get() { diff --git a/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java b/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java index 3753b63525..4dfe195371 100644 --- a/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/core/SchedulerTest.java @@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit; public class SchedulerTest { - private static final String DRIFT_USE_NANOTIME = "rx3.scheduler.use-nanotime"; + private static final String DRIFT_USE_NANOTIME = "rx4.scheduler.use-nanotime"; @After public void cleanup() { diff --git a/src/test/java/io/reactivex/rxjava4/core/XFlatMapTest.java b/src/test/java/io/reactivex/rxjava4/core/XFlatMapTest.java index 76130f44ef..6a04d18c63 100644 --- a/src/test/java/io/reactivex/rxjava4/core/XFlatMapTest.java +++ b/src/test/java/io/reactivex/rxjava4/core/XFlatMapTest.java @@ -72,7 +72,7 @@ public void flowableFlowable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestSubscriber ts = Flowable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap(new Function>() { @Override public Publisher apply(Integer v) throws Exception { @@ -103,7 +103,7 @@ public void flowableSingle() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestSubscriber ts = Flowable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapSingle(new Function>() { @Override public Single apply(Integer v) throws Exception { @@ -134,7 +134,7 @@ public void flowableMaybe() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestSubscriber ts = Flowable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapMaybe(new Function>() { @Override public Maybe apply(Integer v) throws Exception { @@ -165,7 +165,7 @@ public void flowableCompletable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Flowable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -196,7 +196,7 @@ public void flowableCompletable2() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestSubscriber ts = Flowable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -228,7 +228,7 @@ public void observableObservable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Observable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap(new Function>() { @Override public Observable apply(Integer v) throws Exception { @@ -259,7 +259,7 @@ public void observerSingle() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Observable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapSingle(new Function>() { @Override public Single apply(Integer v) throws Exception { @@ -290,7 +290,7 @@ public void observerMaybe() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Observable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapMaybe(new Function>() { @Override public Maybe apply(Integer v) throws Exception { @@ -321,7 +321,7 @@ public void observerCompletable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Observable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -352,7 +352,7 @@ public void observerCompletable2() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Observable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -384,7 +384,7 @@ public void singleSingle() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap(new Function>() { @Override public Single apply(Integer v) throws Exception { @@ -415,7 +415,7 @@ public void singleMaybe() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapMaybe(new Function>() { @Override public Maybe apply(Integer v) throws Exception { @@ -446,7 +446,7 @@ public void singleCompletable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -477,7 +477,7 @@ public void singleCompletable2() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -509,7 +509,7 @@ public void singlePublisher() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestSubscriber ts = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapPublisher(new Function>() { @Override public Publisher apply(Integer v) throws Exception { @@ -540,7 +540,7 @@ public void singleCombiner() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap(new Function>() { @Override public Single apply(Integer v) throws Exception { @@ -571,7 +571,7 @@ public void singleObservable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapObservable(new Function>() { @Override public Observable apply(Integer v) throws Exception { @@ -602,7 +602,7 @@ public void singleNotificationSuccess() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap( new Function>() { @Override @@ -642,7 +642,7 @@ public void singleNotificationError() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Single.error(new TestException()) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap( new Function>() { @Override @@ -682,7 +682,7 @@ public void maybeSingle() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapSingle(new Function>() { @Override public Single apply(Integer v) throws Exception { @@ -714,7 +714,7 @@ public void maybeSingle2() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapSingle(new Function>() { @Override public Single apply(Integer v) throws Exception { @@ -745,7 +745,7 @@ public void maybeMaybe() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap(new Function>() { @Override public Maybe apply(Integer v) throws Exception { @@ -776,7 +776,7 @@ public void maybePublisher() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestSubscriber ts = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapPublisher(new Function>() { @Override public Publisher apply(Integer v) throws Exception { @@ -807,7 +807,7 @@ public void maybeObservable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapObservable(new Function>() { @Override public Observable apply(Integer v) throws Exception { @@ -838,7 +838,7 @@ public void maybeNotificationSuccess() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap( new Function>() { @Override @@ -885,7 +885,7 @@ public void maybeNotificationError() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.error(new TestException()) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap( new Function>() { @Override @@ -932,7 +932,7 @@ public void maybeNotificationEmpty() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.empty() - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap( new Function>() { @Override @@ -979,7 +979,7 @@ public void maybeCombiner() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMap(new Function>() { @Override public Maybe apply(Integer v) throws Exception { @@ -1010,7 +1010,7 @@ public void maybeCompletable() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { @@ -1041,7 +1041,7 @@ public void maybeCompletable2() throws Exception { List errors = TestHelper.trackPluginErrors(); try { TestObserver to = Maybe.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .flatMapCompletable(new Function() { @Override public Completable apply(Integer v) throws Exception { diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java index ea1649742a..669225e42f 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java @@ -177,7 +177,7 @@ public void mergeAsyncThenObserveOnLoop() { incrementingIntegers(c2).subscribeOn(Schedulers.computation())); merged - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .take(num) .subscribe(ts); diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableConversionTest.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableConversionTest.java index 339824f21a..affe44da34 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableConversionTest.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableConversionTest.java @@ -211,7 +211,7 @@ public void convertToConcurrentQueue() { @Override public Publisher apply(final Integer i) { return Flowable.range(0, 5) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .map(new Function() { @Override public Integer apply(Integer k) { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableAndThenCompletableTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableAndThenCompletableTest.java index bfecd582e2..a713fc9961 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableAndThenCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableAndThenCompletableTest.java @@ -152,8 +152,8 @@ public void andThenNoInterrupt() throws InterruptedException { for (int i = 0; i < count; i++) { Completable.complete() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) + .observeOn(Schedulers.cached()) .andThen(Completable.fromAction(new Action() { @Override public void run() throws Exception { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableConcatTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableConcatTest.java index 62e50f3fb5..026785fd66 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableConcatTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableConcatTest.java @@ -284,8 +284,8 @@ public void run() throws Exception { } }); Completable.concat(Arrays.asList(Completable.complete() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.io()), + .subscribeOn(Schedulers.cached()) + .observeOn(Schedulers.cached()), c0) ) .subscribe(new Action() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimeoutTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimeoutTest.java index c4742045ce..7935f28baf 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimeoutTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimeoutTest.java @@ -39,7 +39,7 @@ public class CompletableTimeoutTest extends RxJavaTest { public void timeoutException() throws Exception { Completable.never() - .timeout(100, TimeUnit.MILLISECONDS, Schedulers.io()) + .timeout(100, TimeUnit.MILLISECONDS, Schedulers.cached()) .to(TestHelper.testConsumer()) .awaitDone(5, TimeUnit.SECONDS) .assertFailureAndMessage(TimeoutException.class, timeoutMessage(100, TimeUnit.MILLISECONDS)); @@ -58,7 +58,7 @@ public void run() throws Exception { }); Completable.never() - .timeout(100, TimeUnit.MILLISECONDS, Schedulers.io(), other) + .timeout(100, TimeUnit.MILLISECONDS, Schedulers.cached(), other) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimerTest.java index e8ebb7cf1a..6ce374637d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/completable/CompletableTimerTest.java @@ -37,7 +37,7 @@ public void dispose() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Completable.timer(1, TimeUnit.MILLISECONDS, s) .doOnComplete(new Action() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCacheTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCacheTest.java index 23d9a63da4..d296c392c4 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCacheTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCacheTest.java @@ -185,7 +185,7 @@ public void async() { public void asyncComeAndGo() { Flowable source = Flowable.interval(1, 1, TimeUnit.MILLISECONDS) .take(1000) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); FlowableCache cached = new FlowableCache<>(source, 16); Flowable output = cached.observeOn(Schedulers.computation()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCombineLatestTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCombineLatestTest.java index 1c641d225b..b71d6de880 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCombineLatestTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableCombineLatestTest.java @@ -472,7 +472,7 @@ public List apply(Object[] args) { List> sources = new ArrayList<>(); List values = new ArrayList<>(); for (int j = 0; j < i; j++) { - sources.add(Flowable.just(j).subscribeOn(Schedulers.io())); + sources.add(Flowable.just(j).subscribeOn(Schedulers.cached())); values.add(j); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java index 0c19467843..87a114981c 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java @@ -1126,10 +1126,10 @@ public void oneDelayed() { public Flowable apply(Integer i) throws Exception { return i == 3 ? Flowable.just(i) : Flowable .just(i) - .delay(1, TimeUnit.MILLISECONDS, Schedulers.io()); + .delay(1, TimeUnit.MILLISECONDS, Schedulers.cached()); } }) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1, 2, 3, 4, 5) @@ -1155,7 +1155,7 @@ public void maxConcurrencyOf2() { public Flowable> apply(List v) throws Exception { return Flowable.just(v) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .doOnNext(new Consumer>() { @Override public void accept(List v) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapSchedulerTest.java index 4b05144589..763fba0d0c 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapSchedulerTest.java @@ -1040,7 +1040,7 @@ public void mapperScheduledLong() { public Flowable apply(Integer t) throws Throwable { return Flowable.just(Thread.currentThread().getName()) .repeat(1000) - .observeOn(Schedulers.io()); + .observeOn(Schedulers.cached()); } }, 2, Schedulers.single()) .distinct() @@ -1063,7 +1063,7 @@ public void mapperDelayErrorScheduledLong() { public Flowable apply(Integer t) throws Throwable { return Flowable.just(Thread.currentThread().getName()) .repeat(1000) - .observeOn(Schedulers.io()); + .observeOn(Schedulers.cached()); } }, false, 2, Schedulers.single()) .distinct() @@ -1086,7 +1086,7 @@ public void mapperDelayError2ScheduledLong() { public Flowable apply(Integer t) throws Throwable { return Flowable.just(Thread.currentThread().getName()) .repeat(1000) - .observeOn(Schedulers.io()); + .observeOn(Schedulers.cached()); } }, true, 2, Schedulers.single()) .distinct() diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java index b33778ccd5..2242fa7ef2 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelaySubscriptionOtherTest.java @@ -323,7 +323,7 @@ public Object apply(Flowable f) throws Exception { public void afterDelayNoInterrupt() { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec) }) { final TestSubscriber ts = TestSubscriber.create(); ts.withTag(s.getClass().getSimpleName()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java index 6132a3b314..1db39e2c9e 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java @@ -2461,7 +2461,7 @@ public void fusedGroupClearedOnCancelDelayed() { .flatMap(new Function, Publisher>() { @Override public Publisher apply(GroupedFlowable g) throws Throwable { - return g.observeOn(Schedulers.io()) + return g.observeOn(Schedulers.cached()) .doOnNext(new Consumer() { @Override public void accept(Integer v) throws Throwable { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java index ada9c4ec27..76dea4c497 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java @@ -17,13 +17,13 @@ import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.Flow.*; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; -import io.reactivex.rxjava4.internal.schedulers.IoScheduler; +import io.reactivex.rxjava4.internal.schedulers.CachedScheduler; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.schedulers.Schedulers; import io.reactivex.rxjava4.subscribers.TestSubscriber; @@ -187,7 +187,7 @@ public void simpleOneLess() { @Test public void simpleAsyncLoop() { - IoScheduler ios = (IoScheduler)Schedulers.io(); + CachedScheduler ios = (CachedScheduler)Schedulers.cached(); int c = ios.size(); for (int i = 0; i < 200; i++) { simpleAsync(); @@ -205,7 +205,7 @@ public void simpleAsync() { List> sourceList = new ArrayList<>(i); Set expected = new HashSet<>(i); for (int j = 1; j <= i; j++) { - sourceList.add(Flowable.just(j).subscribeOn(Schedulers.io())); + sourceList.add(Flowable.just(j).subscribeOn(Schedulers.cached())); expected.add(j); } @@ -237,7 +237,7 @@ public void simpleOneLessAsync() { List> sourceList = new ArrayList<>(i); Set expected = new HashSet<>(i); for (int j = 1; j <= i; j++) { - sourceList.add(Flowable.just(j).subscribeOn(Schedulers.io())); + sourceList.add(Flowable.just(j).subscribeOn(Schedulers.cached())); expected.add(j); } @@ -255,9 +255,9 @@ public void simpleOneLessAsync() { public void backpressureHonored() throws Exception { List> sourceList = new ArrayList<>(3); - sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.io())); - sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.io())); - sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.io())); + sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.cached())); + sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.cached())); + sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.cached())); final CountDownLatch cdl = new CountDownLatch(5); @@ -286,9 +286,9 @@ public void onNext(Integer t) { public void take() throws Exception { List> sourceList = new ArrayList<>(3); - sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.io())); - sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.io())); - sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.io())); + sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.cached())); + sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.cached())); + sourceList.add(Flowable.range(0, 100000).subscribeOn(Schedulers.cached())); TestSubscriber ts = new TestSubscriber<>(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java index 16efe86d9f..cd01831fa2 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java @@ -768,7 +768,7 @@ public void accept(long n) { requests.add(n); } }) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .subscribe(new DefaultSubscriber() { @Override @@ -1960,7 +1960,7 @@ public void fusedNoConcurrentCleanDueToCancel() { final UnicastProcessor up = UnicastProcessor.create(); TestObserver to = up.hide() - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .observeOn(Schedulers.single()) .unsubscribeOn(Schedulers.computation()) .firstOrError() diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java index 70fd7158a4..657ad75133 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java @@ -318,7 +318,7 @@ public void fusedNoConcurrentCleanDueToCancel() { final PublishProcessor pp = PublishProcessor.create(); TestObserver to = pp.onBackpressureBuffer(4, false, true) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .map(Functions.identity()) .observeOn(Schedulers.single()) .firstOrError() diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureDropTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureDropTest.java index db6e44bb0f..96dc48fe62 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureDropTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureDropTest.java @@ -45,7 +45,7 @@ public void noBackpressureSupport() { @Test public void withObserveOn() throws InterruptedException { TestSubscriber ts = new TestSubscriber<>(); - Flowable.range(0, Flowable.bufferSize() * 10).onBackpressureDrop().observeOn(Schedulers.io()).subscribe(ts); + Flowable.range(0, Flowable.bufferSize() * 10).onBackpressureDrop().observeOn(Schedulers.cached()).subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureLatestTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureLatestTest.java index 5434413ef0..c295d33848 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureLatestTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureLatestTest.java @@ -190,7 +190,7 @@ public void onNext(Integer t) { Flowable.range(1, m) .subscribeOn(Schedulers.computation()) .onBackpressureLatest() - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .subscribe(ts); ts.awaitDone(2, TimeUnit.SECONDS); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceTest.java index 86de898c26..4e54beaf3e 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceTest.java @@ -179,7 +179,7 @@ public void asynchronousDrop() { //the output sequence of number must be increasing return current; }) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .subscribe(ts); ts.awaitDone(2, TimeUnit.SECONDS); @@ -195,7 +195,7 @@ public void asynchronousDrop2() { Flowable.rangeLong(1, m) .subscribeOn(Schedulers.computation()) .onBackpressureReduce(Long::sum) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .subscribe(ts); ts.awaitDone(2, TimeUnit.SECONDS); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java index 50b14ae05c..63f347ce82 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureReduceWithTest.java @@ -219,7 +219,7 @@ public void asynchronousDrop() { //the output sequence of number must be increasing return Collections.singletonList(current); }) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .concatMap(Flowable::fromIterable) .subscribe(ts); @@ -236,7 +236,7 @@ public void asynchronousDrop2() { Flowable.rangeLong(1, m) .subscribeOn(Schedulers.computation()) .onBackpressureReduce(createTestSupplier(), createTestReducer()) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .concatMap(list -> Flowable.just(list.stream().reduce(Long::sum).orElseThrow(() -> { throw new IllegalArgumentException("No value in list"); }))) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java index f07076dad6..e3973265df 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReduceTest.java @@ -405,7 +405,7 @@ public Publisher apply(final Integer x) throws Exception { public String apply(Integer y) throws Exception { return blockingOp(x, y); } - }).subscribeOn(Schedulers.io()) + }).subscribeOn(Schedulers.cached()) .reduce(new BiFunction() { @Override public String apply(String l, String r) throws Exception { @@ -444,7 +444,7 @@ public Publisher apply(final Integer x) throws Exception { public String apply(Integer y) throws Exception { return blockingOp(x, y); } - }).subscribeOn(Schedulers.io()) + }).subscribeOn(Schedulers.cached()) .reduce(new BiFunction() { @Override public String apply(String l, String r) throws Exception { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableRefCountTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableRefCountTest.java index 17ede43718..b6aa11b0fd 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableRefCountTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableRefCountTest.java @@ -1368,11 +1368,11 @@ public void replayRefCountShallBeThreadSafe() { Flowable flowable = Flowable.just(1).replay(1).refCount(); TestSubscriber ts1 = flowable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); TestSubscriber ts2 = flowable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); ts1 @@ -1442,11 +1442,11 @@ public void publishRefCountShallBeThreadSafe() { Flowable flowable = Flowable.just(1).publish().refCount(); TestSubscriber subscriber1 = flowable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); TestSubscriber subscriber2 = flowable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); subscriber1 diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java index bfeda14450..e1f7d4ba2d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java @@ -1007,7 +1007,7 @@ public void async() { public void asyncComeAndGo() { Flowable source = Flowable.interval(1, 1, TimeUnit.MILLISECONDS) .take(1000) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); Flowable cached = source.replay().autoConnect(); Flowable output = cached.observeOn(Schedulers.computation(), false, 1024); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java index 401bdb1ca5..31cb87c16e 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java @@ -1026,7 +1026,7 @@ public void async() { public void asyncComeAndGo() { Flowable source = Flowable.interval(1, 1, TimeUnit.MILLISECONDS) .take(1000) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); Flowable cached = source.replay().autoConnect(); Flowable output = cached.observeOn(Schedulers.computation(), false, 1024); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java index d4b6c0b7ed..b50a6a60a2 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java @@ -173,7 +173,7 @@ public void skipLastTimedDefaultSchedulerDelayError() { @Test public void skipLastTimedCustomSchedulerDelayError() { Flowable.just(1).concatWith(Flowable.just(2).delay(500, TimeUnit.MILLISECONDS)) - .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.io(), true) + .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.cached(), true) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchIfEmptyTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchIfEmptyTest.java index 3084c30567..8d5c5f58d8 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchIfEmptyTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchIfEmptyTest.java @@ -183,7 +183,7 @@ public void subscribe(final Subscriber subscriber) { @Override public void request(long n) { if (n > 0 && completed.compareAndSet(false, true)) { - Schedulers.io().createWorker().schedule(new Runnable() { + Schedulers.cached().createWorker().schedule(new Runnable() { @Override public void run() { subscriber.onComplete(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java index cfeb305910..d25ed6a800 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java @@ -1366,10 +1366,10 @@ Flowable createFlowable(AtomicInteger inner) { return Flowable.unsafeCreate(s -> { SerializedSubscriber it = new SerializedSubscriber<>(s); it.onSubscribe(new BooleanSubscription()); - Schedulers.io().scheduleDirect(() -> { + Schedulers.cached().scheduleDirect(() -> { it.onNext(1); }, 0, TimeUnit.MILLISECONDS); - Schedulers.io().scheduleDirect(() -> { + Schedulers.cached().scheduleDirect(() -> { it.onNext(2); }, 0, TimeUnit.MILLISECONDS); }) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java index c164cde6dd..582b1cbbe1 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java @@ -267,7 +267,7 @@ public void takeLastTimeDelayError() { @Test public void takeLastTimeDelayErrorCustomScheduler() { Flowable.just(1, 2).concatWith(Flowable.error(new TestException())) - .takeLast(1, TimeUnit.MINUTES, Schedulers.io(), true) + .takeLast(1, TimeUnit.MINUTES, Schedulers.cached(), true) .test() .assertFailure(TestException.class, 1, 2); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTimerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTimerTest.java index 922bd965c7..e8acca3f62 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTimerTest.java @@ -352,7 +352,7 @@ public void timerDelayZero() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestSubscriber ts = Flowable.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithTimeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithTimeTest.java index a08254de13..a432dcd99c 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithTimeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithTimeTest.java @@ -229,7 +229,7 @@ public void accept(Integer pv) { @Test public void timespanTimeskipCustomSchedulerBufferSize() { Flowable.range(1, 10) - .window(1, 1, TimeUnit.MINUTES, Schedulers.io(), 2) + .window(1, 1, TimeUnit.MINUTES, Schedulers.cached(), 2) .flatMap(Functions.>identity()) .test() .awaitDone(5, TimeUnit.SECONDS) @@ -279,7 +279,7 @@ public void timespanTimeskipDefaultScheduler() { @Test public void timespanTimeskipCustomScheduler() { Flowable.just(1) - .window(1, 1, TimeUnit.MINUTES, Schedulers.io()) + .window(1, 1, TimeUnit.MINUTES, Schedulers.cached()) .flatMap(Functions.>identity()) .test() .awaitDone(5, TimeUnit.SECONDS) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeTest.java index 3d5b30efe6..e7f4593b16 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeMergeTest.java @@ -54,7 +54,7 @@ public Integer call() throws Exception { return count.incrementAndGet() - j; } }) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); } for (int i = 0; i < 1000; i++) { @@ -80,7 +80,7 @@ public Integer call() throws Exception { return count.incrementAndGet() - j; } }) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); } sources[1] = Maybe.fromCallable(new Callable() { @Override @@ -88,7 +88,7 @@ public Integer call() throws Exception { throw new TestException("" + count.incrementAndGet()); } }) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); for (int i = 0; i < 1000; i++) { count.set(0); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeTimerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeTimerTest.java index 6c4ef5e995..09ad3494ed 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeTimerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/maybe/MaybeTimerTest.java @@ -37,7 +37,7 @@ public void dispose() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Maybe.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCacheTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCacheTest.java index 4552dfa40c..d22704d138 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCacheTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCacheTest.java @@ -165,7 +165,7 @@ public void async() { public void asyncComeAndGo() { Observable source = Observable.interval(1, 1, TimeUnit.MILLISECONDS) .take(1000) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); ObservableCache cached = new ObservableCache<>(source, 16); Observable output = cached.observeOn(Schedulers.computation()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCombineLatestTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCombineLatestTest.java index 4b67d05ea7..b2c364007d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCombineLatestTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableCombineLatestTest.java @@ -471,7 +471,7 @@ public List apply(Object[] args) { List> sources = new ArrayList<>(); List values = new ArrayList<>(); for (int j = 0; j < i; j++) { - sources.add(Observable.just(j).subscribeOn(Schedulers.io())); + sources.add(Observable.just(j).subscribeOn(Schedulers.cached())); values.add(j); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapEagerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapEagerTest.java index 72378cc379..28199f86cd 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapEagerTest.java @@ -809,10 +809,10 @@ public void oneDelayed() { public ObservableSource apply(Integer i) throws Exception { return i == 3 ? Observable.just(i) : Observable .just(i) - .delay(1, TimeUnit.MILLISECONDS, Schedulers.io()); + .delay(1, TimeUnit.MILLISECONDS, Schedulers.cached()); } }) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1, 2, 3, 4, 5) @@ -838,7 +838,7 @@ public void maxConcurrencyOf2() { public ObservableSource> apply(List v) throws Exception { return Observable.just(v) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .doOnNext(new Consumer>() { @Override public void accept(List v) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapSchedulerTest.java index b3ab5bdbb8..ca37aac3a5 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableConcatMapSchedulerTest.java @@ -952,7 +952,7 @@ public void mapperScheduledLong() { public Observable apply(Integer t) throws Throwable { return Observable.just(Thread.currentThread().getName()) .repeat(1000) - .observeOn(Schedulers.io()); + .observeOn(Schedulers.cached()); } }, 2, Schedulers.single()) .distinct() @@ -975,7 +975,7 @@ public void mapperDelayErrorScheduledLong() { public Observable apply(Integer t) throws Throwable { return Observable.just(Thread.currentThread().getName()) .repeat(1000) - .observeOn(Schedulers.io()); + .observeOn(Schedulers.cached()); } }, false, 2, Schedulers.single()) .distinct() @@ -998,7 +998,7 @@ public void mapperDelayError2ScheduledLong() { public Observable apply(Integer t) throws Throwable { return Observable.just(Thread.currentThread().getName()) .repeat(1000) - .observeOn(Schedulers.io()); + .observeOn(Schedulers.cached()); } }, true, 2, Schedulers.single()) .distinct() diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java index f0077eb069..fcbfadb387 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelaySubscriptionOtherTest.java @@ -208,7 +208,7 @@ public Object apply(Observable o) throws Exception { public void afterDelayNoInterrupt() { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec) }) { final TestObserver observer = TestObserver.create(); observer.withTag(s.getClass().getSimpleName()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableFromTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableFromTest.java index bd1011d191..15dc482f27 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableFromTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableFromTest.java @@ -32,7 +32,7 @@ public class ObservableFromTest extends RxJavaTest { public void fromFutureTimeout() throws Exception { Observable.fromFuture(Observable.never() .toFuture(), 100, TimeUnit.MILLISECONDS) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TimeoutException.class); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeMaxConcurrentTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeMaxConcurrentTest.java index c6fe8154c0..2de9d9f5a5 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeMaxConcurrentTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableMergeMaxConcurrentTest.java @@ -19,13 +19,13 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import io.reactivex.rxjava4.disposables.Disposable; import org.junit.*; import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Observable; import io.reactivex.rxjava4.core.Observer; -import io.reactivex.rxjava4.internal.schedulers.IoScheduler; +import io.reactivex.rxjava4.disposables.Disposable; +import io.reactivex.rxjava4.internal.schedulers.CachedScheduler; import io.reactivex.rxjava4.observers.TestObserver; import io.reactivex.rxjava4.schedulers.Schedulers; import io.reactivex.rxjava4.testsupport.*; @@ -195,7 +195,7 @@ public void simpleOneLess() { @Test public void simpleAsyncLoop() { - IoScheduler ios = (IoScheduler)Schedulers.io(); + CachedScheduler ios = (CachedScheduler)Schedulers.cached(); int c = ios.size(); for (int i = 0; i < 200; i++) { simpleAsync(); @@ -213,7 +213,7 @@ public void simpleAsync() { List> sourceList = new ArrayList<>(i); Set expected = new HashSet<>(i); for (int j = 1; j <= i; j++) { - sourceList.add(Observable.just(j).subscribeOn(Schedulers.io())); + sourceList.add(Observable.just(j).subscribeOn(Schedulers.cached())); expected.add(j); } @@ -245,7 +245,7 @@ public void simpleOneLessAsync() { List> sourceList = new ArrayList<>(i); Set expected = new HashSet<>(i); for (int j = 1; j <= i; j++) { - sourceList.add(Observable.just(j).subscribeOn(Schedulers.io())); + sourceList.add(Observable.just(j).subscribeOn(Schedulers.cached())); expected.add(j); } @@ -263,9 +263,9 @@ public void simpleOneLessAsync() { public void take() throws Exception { List> sourceList = new ArrayList<>(3); - sourceList.add(Observable.range(0, 100000).subscribeOn(Schedulers.io())); - sourceList.add(Observable.range(0, 100000).subscribeOn(Schedulers.io())); - sourceList.add(Observable.range(0, 100000).subscribeOn(Schedulers.io())); + sourceList.add(Observable.range(0, 100000).subscribeOn(Schedulers.cached())); + sourceList.add(Observable.range(0, 100000).subscribeOn(Schedulers.cached())); + sourceList.add(Observable.range(0, 100000).subscribeOn(Schedulers.cached())); TestObserver to = new TestObserver<>(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableObserveOnTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableObserveOnTest.java index 59f7a914e1..033a52fd94 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableObserveOnTest.java @@ -825,7 +825,7 @@ public void fusedNoConcurrentCleanDueToCancel() { final UnicastSubject us = UnicastSubject.create(); TestObserver to = us.hide() - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .observeOn(Schedulers.single()) .unsubscribeOn(Schedulers.computation()) .firstOrError() diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableRefCountTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableRefCountTest.java index a7391ca695..4fdbf1a601 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableRefCountTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableRefCountTest.java @@ -1321,11 +1321,11 @@ public void replayRefCountShallBeThreadSafe() { Observable observable = Observable.just(1).replay(1).refCount(); TestObserver observer1 = observable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); TestObserver observer2 = observable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); observer1 @@ -1395,11 +1395,11 @@ public void publishRefCountShallBeThreadSafe() { Observable observable = Observable.just(1).publish().refCount(); TestObserver observer1 = observable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); TestObserver observer2 = observable - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test(); observer1 diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayEagerTruncateTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayEagerTruncateTest.java index 240a889b2c..de8f9c2601 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayEagerTruncateTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayEagerTruncateTest.java @@ -990,7 +990,7 @@ public void async() { public void asyncComeAndGo() { Observable source = Observable.interval(1, 1, TimeUnit.MILLISECONDS) .take(1000) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); Observable cached = source.replay().autoConnect(); Observable output = cached.observeOn(Schedulers.computation()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayTest.java index 2d9932aa43..fb7008e2d5 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplayTest.java @@ -990,7 +990,7 @@ public void async() { public void asyncComeAndGo() { Observable source = Observable.interval(1, 1, TimeUnit.MILLISECONDS) .take(1000) - .subscribeOn(Schedulers.io()); + .subscribeOn(Schedulers.cached()); Observable cached = source.replay().autoConnect(); Observable output = cached.observeOn(Schedulers.computation()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java index d3610430e4..6c3ec37e43 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java @@ -172,7 +172,7 @@ public void skipLastTimedDefaultSchedulerDelayError() { @Test public void skipLastTimedCustomSchedulerDelayError() { Observable.just(1).concatWith(Observable.just(2).delay(500, TimeUnit.MILLISECONDS)) - .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.io(), true) + .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.cached(), true) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSwitchTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSwitchTest.java index 4dee50754d..932e26f307 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSwitchTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSwitchTest.java @@ -1428,10 +1428,10 @@ Observable createObservable(AtomicInteger inner) { @SuppressWarnings("resource") SerializedObserver it = new SerializedObserver<>(s); it.onSubscribe(Disposable.empty()); - Schedulers.io().scheduleDirect(() -> { + Schedulers.cached().scheduleDirect(() -> { it.onNext(1); }, 0, TimeUnit.MILLISECONDS); - Schedulers.io().scheduleDirect(() -> { + Schedulers.cached().scheduleDirect(() -> { it.onNext(2); }, 0, TimeUnit.MILLISECONDS); }) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java index 8951096499..1f944bf07a 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java @@ -229,7 +229,7 @@ public void takeLastTimeDelayError() { @Test public void takeLastTimeDelayErrorCustomScheduler() { Observable.just(1, 2).concatWith(Observable.error(new TestException())) - .takeLast(1, TimeUnit.MINUTES, Schedulers.io(), true) + .takeLast(1, TimeUnit.MINUTES, Schedulers.cached(), true) .test() .assertFailure(TestException.class, 1, 2); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTimerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTimerTest.java index acee0cd72c..f54e78dbd9 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTimerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTimerTest.java @@ -317,7 +317,7 @@ public void timerDelayZero() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Observable.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableWindowWithTimeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableWindowWithTimeTest.java index 7423b71cda..588618fcd7 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableWindowWithTimeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableWindowWithTimeTest.java @@ -238,7 +238,7 @@ public void timespanTimeskipDefaultScheduler() { @Test public void timespanTimeskipCustomScheduler() { Observable.just(1) - .window(1, 1, TimeUnit.MINUTES, Schedulers.io()) + .window(1, 1, TimeUnit.MINUTES, Schedulers.cached()) .flatMap(Functions.>identity()) .test() .awaitDone(5, TimeUnit.SECONDS) @@ -248,7 +248,7 @@ public void timespanTimeskipCustomScheduler() { @Test public void timespanTimeskipCustomSchedulerBufferSize() { Observable.range(1, 10) - .window(1, 1, TimeUnit.MINUTES, Schedulers.io(), 2) + .window(1, 1, TimeUnit.MINUTES, Schedulers.cached(), 2) .flatMap(Functions.>identity()) .test() .awaitDone(5, TimeUnit.SECONDS) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleDelayTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleDelayTest.java index 7ac9ff9156..ae5a648396 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleDelayTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleDelayTest.java @@ -129,7 +129,7 @@ public void delaySubscriptionTime() throws Exception { @Test public void delaySubscriptionTimeCustomScheduler() throws Exception { - Single.just(1).delaySubscription(100, TimeUnit.MILLISECONDS, Schedulers.io()) + Single.just(1).delaySubscription(100, TimeUnit.MILLISECONDS, Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleFromTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleFromTest.java index 347dc725ba..e942b99467 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleFromTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleFromTest.java @@ -25,7 +25,7 @@ public class SingleFromTest extends RxJavaTest { @Test public void fromFuture() throws Exception { Single.fromFuture(Flowable.just(1).toFuture()) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); @@ -34,7 +34,7 @@ public void fromFuture() throws Exception { @Test public void fromFutureTimeout() throws Exception { Single.fromFuture(Flowable.never().toFuture(), 1, TimeUnit.SECONDS) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TimeoutException.class); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleMiscTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleMiscTest.java index 3f16e83b58..15e91d38e7 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleMiscTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleMiscTest.java @@ -237,7 +237,7 @@ public boolean test(Throwable e) throws Exception { @Test public void timeout() throws Exception { - Single.never().timeout(100, TimeUnit.MILLISECONDS, Schedulers.io()) + Single.never().timeout(100, TimeUnit.MILLISECONDS, Schedulers.cached()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TimeoutException.class); @@ -246,7 +246,7 @@ public void timeout() throws Exception { @Test public void timeoutOther() throws Exception { Single.never() - .timeout(100, TimeUnit.MILLISECONDS, Schedulers.io(), Single.just(1)) + .timeout(100, TimeUnit.MILLISECONDS, Schedulers.cached(), Single.just(1)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleTimerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleTimerTest.java index 76ae6103bb..cca87b772a 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleTimerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/single/SingleTimerTest.java @@ -37,7 +37,7 @@ public void disposed() { public void timerInterruptible() throws Exception { ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); try { - for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.io(), Schedulers.from(exec, true) }) { + for (Scheduler s : new Scheduler[] { Schedulers.single(), Schedulers.computation(), Schedulers.newThread(), Schedulers.cached(), Schedulers.from(exec, true) }) { final AtomicBoolean interrupted = new AtomicBoolean(); TestObserver to = Single.timer(1, TimeUnit.MILLISECONDS, s) .map(new Function() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/schedulers/IoScheduledReleaseTest.java b/src/test/java/io/reactivex/rxjava4/internal/schedulers/CachedScheduledReleaseTest.java similarity index 75% rename from src/test/java/io/reactivex/rxjava4/internal/schedulers/IoScheduledReleaseTest.java rename to src/test/java/io/reactivex/rxjava4/internal/schedulers/CachedScheduledReleaseTest.java index ad8762aeb4..6f40049176 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/schedulers/IoScheduledReleaseTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/schedulers/CachedScheduledReleaseTest.java @@ -21,21 +21,21 @@ import java.util.concurrent.TimeUnit; -public class IoScheduledReleaseTest extends RxJavaTest { +public class CachedScheduledReleaseTest extends RxJavaTest { - /* This test will be stuck in a deadlock if IoScheduler.USE_SCHEDULED_RELEASE is not set */ + /* This test will be stuck in a deadlock if CachedScheduler.USE_SCHEDULED_RELEASE is not set */ @Test public void scheduledRelease() { - boolean savedScheduledRelease = IoScheduler.USE_SCHEDULED_RELEASE; - IoScheduler.USE_SCHEDULED_RELEASE = true; + boolean savedScheduledRelease = CachedScheduler.USE_SCHEDULED_RELEASE; + CachedScheduler.USE_SCHEDULED_RELEASE = true; try { Flowable.just("item") - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .firstOrError() .map(_ -> { for (int i = 0; i < 50; i++) { Completable.complete() - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .blockingAwait(); } return "Done"; @@ -45,7 +45,7 @@ public void scheduledRelease() { .awaitDone(5, TimeUnit.SECONDS) .assertComplete(); } finally { - IoScheduler.USE_SCHEDULED_RELEASE = savedScheduledRelease; + CachedScheduler.USE_SCHEDULED_RELEASE = savedScheduledRelease; } } } diff --git a/src/test/java/io/reactivex/rxjava4/internal/schedulers/IoSchedulerInternalTest.java b/src/test/java/io/reactivex/rxjava4/internal/schedulers/CachedSchedulerInternalTest.java similarity index 95% rename from src/test/java/io/reactivex/rxjava4/internal/schedulers/IoSchedulerInternalTest.java rename to src/test/java/io/reactivex/rxjava4/internal/schedulers/CachedSchedulerInternalTest.java index 7d043be300..2d6b894dd2 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/schedulers/IoSchedulerInternalTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/schedulers/CachedSchedulerInternalTest.java @@ -14,16 +14,17 @@ package io.reactivex.rxjava4.internal.schedulers; import static org.junit.Assert.*; + import java.util.concurrent.ConcurrentLinkedQueue; import org.junit.Test; import io.reactivex.rxjava4.core.RxJavaTest; import io.reactivex.rxjava4.disposables.CompositeDisposable; -import io.reactivex.rxjava4.internal.schedulers.IoScheduler.*; +import io.reactivex.rxjava4.internal.schedulers.CachedScheduler.*; import io.reactivex.rxjava4.testsupport.TestHelper; -public class IoSchedulerInternalTest extends RxJavaTest { +public class CachedSchedulerInternalTest extends RxJavaTest { @Test public void expiredQueueEmpty() { diff --git a/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java b/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java index 8904a720f3..37c092a048 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/subscribers/DeferredScalarSubscriberTest.java @@ -342,8 +342,8 @@ public void run() { @Test public void emissionRequestRace2() { - Worker w = Schedulers.io().createWorker(); - Worker w2 = Schedulers.io().createWorker(); + Worker w = Schedulers.cached().createWorker(); + Worker w2 = Schedulers.cached().createWorker(); int m = 10000; if (Runtime.getRuntime().availableProcessors() < 3) { m = 1000; diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java new file mode 100644 index 0000000000..ad61075bbf --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +/* + * Copyright 2019-Present David Karnok + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual; + +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.schedulers.Schedulers; + +public class VirtualCreateVirtualTest { + + @Test + public void checkIsInsideVirtualThread() { + Flowable.virtualCreate(emitter -> { + emitter.emit(Thread.currentThread().isVirtual()); + }) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(true); + } + + @Test + public void checkIsInsideVirtualThreadExec() throws Throwable { + Flowable.virtualCreate(emitter -> { + emitter.emit(Thread.currentThread().isVirtual()); + }, Schedulers.cached()) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(false); + } + + @Test + public void plainVirtual() { + var result = new AtomicReference(); + try (var scope = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory())) { + scope.submit(() -> result.set(Thread.currentThread().isVirtual())); + } + + assertTrue(result.get()); + } + + @Test + public void takeUntil() throws Throwable { + Flowable.virtualCreate(e -> { + for (int i = 1; i < 6; i++) { + e.emit(i); + } + }) + .take(2) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1, 2); + } + + @Test + public void backpressure() throws Throwable { + Flowable.virtualCreate(e -> { + for (int i = 0; i < 10000; i++) { + e.emit(i); + } + }) + .observeOn(Schedulers.single(), false, 2) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertValueCount(10000) + ; + } + + @Test + public void error() throws Throwable { + Flowable.virtualCreate(_ -> { + throw new IOException(); + }) + .observeOn(Schedulers.single(), false, 2) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertError(IOException.class) + ; + } +} diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java new file mode 100644 index 0000000000..9e891ed5dd --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual; + +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.schedulers.Schedulers; + +public class VirtualTransformVirtualTest { + + @Test + public void checkIsInsideVirtualThread() { + var cancelled = new AtomicBoolean(); + Flowable.range(1, 5) + .doOnCancel(() -> cancelled.set(true)) + .virtualTransform((v, emitter) -> emitter.emit(v)) + .take(1) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1); + + assertTrue(cancelled.get()); + } + + @Test + public void errorUpstream() throws Throwable { + Flowable.error(new IOException()) + .virtualTransform((v, e) -> e.emit(v)) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertError(IOException.class) + ; + } + + @Test + public void errorTransform() throws Throwable { + Flowable.range(1, 5) + .virtualTransform((_, _) -> { throw new IOException(); }) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertError(IOException.class) + ; + } + + @Test + public void take() throws Throwable { + Flowable.range(1, 5) + .virtualTransform((v, e) -> e.emit(v)) + .take(2) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1, 2) + ; + } + + @Test + public void observeOn() throws Throwable { + Flowable.range(1, 10000) + .virtualTransform((v, e) -> e.emit(v)) + .observeOn(Schedulers.single(), false, 2) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertNoErrors() + .assertValueCount(10000); + } + + @Test + public void empty() throws Throwable { + Flowable.empty() + .virtualTransform((v, e) -> e.emit(v)) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult() + ; + } + + @Test + public void emptyNever() throws Throwable { + Flowable.just(1).concatWith(Flowable.never()) + .virtualTransform((v, e) -> e.emit(v)) + .test() + .awaitDone(1, TimeUnit.SECONDS) + .assertValues(1) + ; + } +} diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualCreateVirtualTckTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualCreateVirtualTckTest.java new file mode 100644 index 0000000000..f495197144 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualCreateVirtualTckTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual.tck; + +import java.io.IOException; +import java.util.concurrent.Flow.Publisher; + +import org.testng.annotations.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.tck.BaseTck; + +@Test +public class FlowableVirtualCreateVirtualTckTest extends BaseTck { + + @Override + public Publisher createFlowPublisher(final long elements) { + return + Flowable.virtualCreate(emitter -> { + for (var i = 0L; i < elements; i++) { + emitter.emit(i); + } + }); + } + + @Override + public Publisher createFailedFlowPublisher() { + return Flowable.virtualCreate(_ -> { + throw new IOException(); + }); + } +} diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual1TckTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual1TckTest.java new file mode 100644 index 0000000000..c07e22943d --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual1TckTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual.tck; + +import java.io.IOException; +import java.util.concurrent.Flow.Publisher; + +import org.testng.annotations.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.schedulers.Schedulers; +import io.reactivex.rxjava4.tck.BaseTck; + +@Test +public class FlowableVirtualTransformVirtual1TckTest extends BaseTck { + + @Override + public Publisher createFlowPublisher(final long elements) { + var half = elements >> 1; + var rest = elements - half; + return Flowable.rangeLong(0, rest) + .virtualTransform((v, emitter) -> { + emitter.emit(v); + if (v < rest - 1 || half == rest) { + emitter.emit(v); + } + }, Schedulers.virtual(), 1); + } + + @Override + public Publisher createFailedFlowPublisher() { + return Flowable.just(1) + .virtualTransform((_, _) -> { + throw new IOException(); + }, Schedulers.virtual(), 1); + } +} diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual2TckTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual2TckTest.java new file mode 100644 index 0000000000..d478809845 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual2TckTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual.tck; + +import java.io.IOException; +import java.util.concurrent.Flow.Publisher; +import java.util.concurrent.TimeUnit; + +import org.testng.annotations.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.schedulers.Schedulers; +import io.reactivex.rxjava4.tck.BaseTck; + +@Test +public class FlowableVirtualTransformVirtual2TckTest extends BaseTck { + + @Override + public Publisher createFlowPublisher(final long elements) { + var half = elements >> 1; + var rest = elements - half; + return Flowable.rangeLong(0, rest) + .virtualTransform((v, emitter) -> { + emitter.emit(v); + if (v < rest - 1 || half == rest) { + emitter.emit(v); + } + }, Schedulers.virtual(), 2); + } + + @Override + public Publisher createFailedFlowPublisher() { + return Flowable.just(1) + .virtualTransform((_, _) -> { + throw new IOException(); + }, Schedulers.virtual(), 2); + } + + @Test + public void slowProducer() { + Flowable.range(1, 10) + .subscribeOn(Schedulers.computation()) + .map(v -> { + Thread.interrupted(); + Thread.sleep(10); + return v; + }) + .virtualTransform((v, emitter) -> { + emitter.emit(v); + }, Schedulers.virtual(), 2) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } +} diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual3TckTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual3TckTest.java new file mode 100644 index 0000000000..31861a3d5b --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtual3TckTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual.tck; + +import java.io.IOException; +import java.util.concurrent.Flow.Publisher; + +import org.testng.annotations.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.schedulers.Schedulers; +import io.reactivex.rxjava4.tck.BaseTck; + +@Test +public class FlowableVirtualTransformVirtual3TckTest extends BaseTck { + + @Override + public Publisher createFlowPublisher(final long elements) { + var half = elements >> 1; + var rest = elements - half; + return Flowable.rangeLong(0, rest) + .virtualTransform((v, emitter) -> { + emitter.emit(v); + if (v < rest - 1 || half == rest) { + emitter.emit(v); + } + }, Schedulers.virtual(), Flowable.bufferSize()); + } + + @Override + public Publisher createFailedFlowPublisher() { + return Flowable.error(new IOException()) + .virtualTransform((_, _) -> { + }, Schedulers.virtual(), Flowable.bufferSize()); + } +} diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtualTckTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtualTckTest.java new file mode 100644 index 0000000000..ee42e56d96 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/tck/FlowableVirtualTransformVirtualTckTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.internal.virtual.tck; + +import java.io.IOException; +import java.util.concurrent.*; +import java.util.concurrent.Flow.Publisher; + +import org.testng.annotations.Test; + +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.schedulers.Schedulers; +import io.reactivex.rxjava4.tck.BaseTck; +import io.reactivex.rxjava4.testsupport.TestHelper; + +@Test +public class FlowableVirtualTransformVirtualTckTest extends BaseTck { + + @Override + public Publisher createFlowPublisher(final long elements) { + var half = elements >> 1; + var rest = elements - half; + return Flowable.rangeLong(0, rest) + .virtualTransform((v, emitter) -> { + emitter.emit(v); + if (v < rest - 1 || half == rest) { + emitter.emit(v); + } + }, Schedulers.virtual(), Flowable.bufferSize()); + } + + @Override + public Publisher createFailedFlowPublisher() { + return Flowable.just(1) + .virtualTransform((_, _) -> { + throw new IOException(); + }, Schedulers.virtual(), Flowable.bufferSize()); + } + + @Test + public void slowProducer() { + var log = new ConcurrentLinkedQueue(); + + var ts = Flowable.range(1, 10) + .doOnNext(v -> log.offer("Range: " + v)) + .doOnRequest(v -> log.offer("SubscribeOn requested: " + v)) + .doOnSubscribe(_ -> log.offer("Range subscribed to")) + .subscribeOn(Schedulers.computation()) + .doOnRequest(v -> log.offer("Map requested: " + v)) + .doOnSubscribe(_ -> log.offer("subscribeOn subscribed to")) + .map(v -> { + log.offer("Map: " + v); + log.offer("Map interrupted? " + Thread.interrupted()); + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + log.offer("Map sleep interrupted"); + } + return v; + }) + .doOnRequest(v -> log.offer("Transform requested: " + v)) + .virtualTransform((v, emitter) -> { + log.offer("Tansform before emit: " + v); + emitter.emit(v); + log.offer("Tansform after emit: " + v); + }, Schedulers.virtual(), Flowable.bufferSize()) + .doOnRequest(v -> log.offer("Test requested: " + v)) + .doOnNext(v -> log.offer("Test received: " + v)) + .test() + .awaitDone(5, TimeUnit.SECONDS) + ; + + try { + ts.assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } catch (AssertionError ex) { + var sb = new StringBuilder(); + log.forEach(v -> sb.append("\r\n").append(v)); + var exc = new AssertionError(sb.append("\r\n").toString(), ex); + throw exc; + } + } + + @Test + public void slowProducerService() { + TestHelper.checkObstruction(); + + Flowable.range(1, 10) + .subscribeOn(Schedulers.computation()) + .map(v -> { + Thread.interrupted(); + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + // ignored + } + return v; + }) + .virtualTransform((v, emitter) -> { + emitter.emit(v); + }, Schedulers.virtual(), Flowable.bufferSize()) + .test() + .awaitDone(5, TimeUnit.SECONDS) + .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } +} diff --git a/src/test/java/io/reactivex/rxjava4/plugins/RxJavaPluginsTest.java b/src/test/java/io/reactivex/rxjava4/plugins/RxJavaPluginsTest.java index 9a3fa5dc3b..8c03225fc3 100644 --- a/src/test/java/io/reactivex/rxjava4/plugins/RxJavaPluginsTest.java +++ b/src/test/java/io/reactivex/rxjava4/plugins/RxJavaPluginsTest.java @@ -20,16 +20,16 @@ import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.Flow.*; import java.util.concurrent.atomic.*; import org.junit.Test; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Observable; import io.reactivex.rxjava4.core.Observer; import io.reactivex.rxjava4.core.Scheduler.Worker; -import io.reactivex.rxjava4.disposables.*; +import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.flowables.ConnectableFlowable; import io.reactivex.rxjava4.functions.*; @@ -176,16 +176,16 @@ public void overrideComputationScheduler() { } @Test - public void overrideIoScheduler() { + public void overrideCachedScheduler() { try { - RxJavaPlugins.setIoSchedulerHandler(replaceWithImmediate); + RxJavaPlugins.setCachedSchedulerHandler(replaceWithImmediate); - assertSame(ImmediateThinScheduler.INSTANCE, Schedulers.io()); + assertSame(ImmediateThinScheduler.INSTANCE, Schedulers.cached()); } finally { RxJavaPlugins.reset(); } // make sure the reset worked - assertNotSame(ImmediateThinScheduler.INSTANCE, Schedulers.io()); + assertNotSame(ImmediateThinScheduler.INSTANCE, Schedulers.cached()); } @Test @@ -249,8 +249,8 @@ public Scheduler get() throws Exception { } @Test - public void overrideInitIoScheduler() { - final Scheduler s = Schedulers.io(); // make sure the Schedulers is initialized; + public void overrideInitCachedScheduler() { + final Scheduler s = Schedulers.cached(); // make sure the Schedulers is initialized; Supplier c = new Supplier() { @Override public Scheduler get() throws Exception { @@ -258,14 +258,34 @@ public Scheduler get() throws Exception { } }; try { - RxJavaPlugins.setInitIoSchedulerHandler(initReplaceWithImmediate); + RxJavaPlugins.setInitCachedSchedulerHandler(initReplaceWithImmediate); - assertSame(ImmediateThinScheduler.INSTANCE, RxJavaPlugins.initIoScheduler(c)); + assertSame(ImmediateThinScheduler.INSTANCE, RxJavaPlugins.initCachedScheduler(c)); } finally { RxJavaPlugins.reset(); } // make sure the reset worked - assertSame(s, RxJavaPlugins.initIoScheduler(c)); + assertSame(s, RxJavaPlugins.initCachedScheduler(c)); + } + + @Test + public void overrideInitVirtualScheduler() { + final Scheduler s = Schedulers.virtual(); // make sure the Schedulers is initialized; + Supplier c = new Supplier() { + @Override + public Scheduler get() throws Exception { + return s; + } + }; + try { + RxJavaPlugins.setInitVirtualSchedulerHandler(initReplaceWithImmediate); + + assertSame(ImmediateThinScheduler.INSTANCE, RxJavaPlugins.initVirtualScheduler(c)); + } finally { + RxJavaPlugins.reset(); + } + // make sure the reset worked + assertSame(s, RxJavaPlugins.initVirtualScheduler(c)); } @Test @@ -334,10 +354,10 @@ public void overrideInitComputationSchedulerCrashes() { } @Test - public void overrideInitIoSchedulerCrashes() { + public void overrideInitCachedSchedulerCrashes() { // fail when Supplier is null try { - RxJavaPlugins.initIoScheduler(null); + RxJavaPlugins.initCachedScheduler(null); fail("Should have thrown NullPointerException"); } catch (NullPointerException npe) { assertEquals("Scheduler Supplier can't be null", npe.getMessage()); @@ -345,7 +365,26 @@ public void overrideInitIoSchedulerCrashes() { // fail when Supplier result is null try { - RxJavaPlugins.initIoScheduler(nullResultSupplier); + RxJavaPlugins.initCachedScheduler(nullResultSupplier); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException npe) { + assertEquals("Scheduler Supplier result can't be null", npe.getMessage()); + } + } + + @Test + public void overrideInitVirtualSchedulerCrashes() { + // fail when Supplier is null + try { + RxJavaPlugins.initVirtualScheduler(null); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException npe) { + assertEquals("Scheduler Supplier can't be null", npe.getMessage()); + } + + // fail when Supplier result is null + try { + RxJavaPlugins.initVirtualScheduler(nullResultSupplier); fail("Should have thrown NullPointerException"); } catch (NullPointerException npe) { assertEquals("Scheduler Supplier result can't be null", npe.getMessage()); @@ -394,17 +433,31 @@ public void defaultSingleSchedulerIsInitializedLazily() { } @Test - public void defaultIoSchedulerIsInitializedLazily() { + public void defaultCachedSchedulerIsInitializedLazily() { // unsafe default Scheduler Supplier should not be evaluated try { - RxJavaPlugins.setInitIoSchedulerHandler(initReplaceWithImmediate); - RxJavaPlugins.initIoScheduler(unsafeDefault); + RxJavaPlugins.setInitCachedSchedulerHandler(initReplaceWithImmediate); + RxJavaPlugins.initCachedScheduler(unsafeDefault); } finally { RxJavaPlugins.reset(); } // make sure the reset worked - assertNotSame(ImmediateThinScheduler.INSTANCE, Schedulers.io()); + assertNotSame(ImmediateThinScheduler.INSTANCE, Schedulers.cached()); + } + + @Test + public void defaultVirtualSchedulerIsInitializedLazily() { + // unsafe default Scheduler Supplier should not be evaluated + try { + RxJavaPlugins.setInitVirtualSchedulerHandler(initReplaceWithImmediate); + RxJavaPlugins.initVirtualScheduler(unsafeDefault); + } finally { + RxJavaPlugins.reset(); + } + + // make sure the reset worked + assertNotSame(ImmediateThinScheduler.INSTANCE, Schedulers.virtual()); } @Test @@ -846,7 +899,7 @@ public void onScheduleComputation() throws InterruptedException { @Test public void onScheduleIO() throws InterruptedException { - onSchedule(Schedulers.io().createWorker()); + onSchedule(Schedulers.cached().createWorker()); } @Test @@ -1102,7 +1155,8 @@ public Completable apply(Completable completable) throws Exception { RxJavaPlugins.setInitComputationSchedulerHandler(callable2scheduler); RxJavaPlugins.setComputationSchedulerHandler(scheduler2scheduler); - RxJavaPlugins.setIoSchedulerHandler(scheduler2scheduler); + RxJavaPlugins.setCachedSchedulerHandler(scheduler2scheduler); + RxJavaPlugins.setVirtualSchedulerHandler(scheduler2scheduler); RxJavaPlugins.setNewThreadSchedulerHandler(scheduler2scheduler); RxJavaPlugins.setOnConnectableFlowableAssembly(connectableFlowable2ConnectableFlowable); RxJavaPlugins.setOnConnectableObservableAssembly(connectableObservable2ConnectableObservable); @@ -1121,7 +1175,8 @@ public Completable apply(Completable completable) throws Exception { RxJavaPlugins.setOnCompletableAssembly(completable2completable); RxJavaPlugins.setInitSingleSchedulerHandler(callable2scheduler); RxJavaPlugins.setInitNewThreadSchedulerHandler(callable2scheduler); - RxJavaPlugins.setInitIoSchedulerHandler(callable2scheduler); + RxJavaPlugins.setInitCachedSchedulerHandler(callable2scheduler); + RxJavaPlugins.setInitVirtualSchedulerHandler(callable2scheduler); } finally { RxJavaPlugins.reset(); } @@ -1265,7 +1320,9 @@ public Scheduler get() throws Exception { }; assertSame(s, RxJavaPlugins.onComputationScheduler(s)); - assertSame(s, RxJavaPlugins.onIoScheduler(s)); + assertSame(s, RxJavaPlugins.onCachedScheduler(s)); + + assertSame(s, RxJavaPlugins.onVirtualScheduler(s)); assertSame(s, RxJavaPlugins.onNewThreadScheduler(s)); @@ -1273,7 +1330,9 @@ public Scheduler get() throws Exception { assertSame(s, RxJavaPlugins.initComputationScheduler(c)); - assertSame(s, RxJavaPlugins.initIoScheduler(c)); + assertSame(s, RxJavaPlugins.initCachedScheduler(c)); + + assertSame(s, RxJavaPlugins.initVirtualScheduler(c)); assertSame(s, RxJavaPlugins.initNewThreadScheduler(c)); @@ -1656,8 +1715,8 @@ public Scheduler apply(Scheduler scheduler) throws Exception { } @Test - public void createIoScheduler() { - final String name = "IoSchedulerTest"; + public void createCachedScheduler() { + final String name = "CachedSchedulerTest"; ThreadFactory factory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { @@ -1665,8 +1724,8 @@ public Thread newThread(Runnable r) { } }; - final Scheduler customScheduler = RxJavaPlugins.createIoScheduler(factory); - RxJavaPlugins.setIoSchedulerHandler(new Function() { + final Scheduler customScheduler = RxJavaPlugins.createCachedScheduler(factory); + RxJavaPlugins.setCachedSchedulerHandler(new Function() { @Override public Scheduler apply(Scheduler scheduler) throws Exception { return customScheduler; @@ -1674,7 +1733,7 @@ public Scheduler apply(Scheduler scheduler) throws Exception { }); try { - verifyThread(Schedulers.io(), name); + verifyThread(Schedulers.cached(), name); } finally { customScheduler.shutdown(); RxJavaPlugins.reset(); diff --git a/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java b/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java index a97f9ea995..ed6ccdca37 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/BehaviorProcessorTest.java @@ -365,8 +365,8 @@ public void takeOneSubscriber() { @Test public void emissionSubscriptionRace() throws Exception { - Scheduler s = Schedulers.io(); - Scheduler.Worker worker = Schedulers.io().createWorker(); + Scheduler s = Schedulers.cached(); + Scheduler.Worker worker = Schedulers.cached().createWorker(); try { for (int i = 0; i < 50000; i++) { if (i % 1000 == 0) { @@ -391,7 +391,7 @@ public void run() { final AtomicReference o = new AtomicReference<>(); - rs.subscribeOn(s).observeOn(Schedulers.io()) + rs.subscribeOn(s).observeOn(Schedulers.cached()) .subscribe(new DefaultSubscriber() { @Override diff --git a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java index 55231adaf5..cbf1e2b88e 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorBoundedConcurrencyTest.java @@ -323,8 +323,8 @@ public void run() { @Test public void replaySubjectEmissionSubscriptionRace() throws Exception { - Scheduler s = Schedulers.io(); - Scheduler.Worker worker = Schedulers.io().createWorker(); + Scheduler s = Schedulers.cached(); + Scheduler.Worker worker = Schedulers.cached().createWorker(); try { for (int i = 0; i < 50000; i++) { if (i % 1000 == 0) { @@ -356,7 +356,7 @@ public void run() { // .doOnSubscribe(v -> System.out.println("!! " + j)) // .doOnNext(e -> System.out.println(">> " + j)) .subscribeOn(s) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) // .doOnNext(e -> System.out.println(">>> " + j)) .subscribe(new DefaultSubscriber() { diff --git a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java index 596080afa0..78b2f7ae28 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/ReplayProcessorConcurrencyTest.java @@ -323,8 +323,8 @@ public void run() { @Test public void replaySubjectEmissionSubscriptionRace() throws Exception { - Scheduler s = Schedulers.io(); - Scheduler.Worker worker = Schedulers.io().createWorker(); + Scheduler s = Schedulers.cached(); + Scheduler.Worker worker = Schedulers.cached().createWorker(); try { for (int i = 0; i < 50000; i++) { if (i % 1000 == 0) { @@ -349,7 +349,7 @@ public void run() { final AtomicReference o = new AtomicReference<>(); - rs.subscribeOn(s).observeOn(Schedulers.io()) + rs.subscribeOn(s).observeOn(Schedulers.cached()) .subscribe(new DefaultSubscriber() { @Override diff --git a/src/test/java/io/reactivex/rxjava4/processors/UnicastProcessorTest.java b/src/test/java/io/reactivex/rxjava4/processors/UnicastProcessorTest.java index f156748a8e..01bc148d0a 100644 --- a/src/test/java/io/reactivex/rxjava4/processors/UnicastProcessorTest.java +++ b/src/test/java/io/reactivex/rxjava4/processors/UnicastProcessorTest.java @@ -452,7 +452,7 @@ public void fusedNoConcurrentCleanDueToCancel() { final UnicastProcessor up = UnicastProcessor.create(); TestObserver to = up - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .map(Functions.identity()) .observeOn(Schedulers.single()) .firstOrError() diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java index cc08f13415..4c086a6970 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java @@ -21,23 +21,23 @@ import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Scheduler.Worker; -import io.reactivex.rxjava4.disposables.*; +import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.functions.*; -import io.reactivex.rxjava4.internal.schedulers.IoScheduler; +import io.reactivex.rxjava4.internal.schedulers.CachedScheduler; import io.reactivex.rxjava4.testsupport.SuppressUndeliverable; public class CachedThreadSchedulerTest extends AbstractSchedulerConcurrencyTests { @Override protected Scheduler getScheduler() { - return Schedulers.io(); + return Schedulers.cached(); } /** * IO scheduler defaults to using CachedThreadScheduler. */ @Test - public final void iOScheduler() { + public final void cachedScheduler() { Flowable f1 = Flowable.just(1, 2, 3, 4, 5); Flowable f2 = Flowable.just(6, 7, 8, 9, 10); @@ -50,7 +50,7 @@ public String apply(Integer t) { } }); - f.subscribeOn(Schedulers.io()).blockingForEach(new Consumer() { + f.subscribeOn(Schedulers.cached()).blockingForEach(new Consumer() { @Override public void accept(String t) { @@ -66,13 +66,13 @@ public final void handledErrorIsNotDeliveredToThreadHandler() throws Interrupted @Test public void cancelledTaskRetention() throws InterruptedException { - Worker w = Schedulers.io().createWorker(); + Worker w = Schedulers.cached().createWorker(); try { ExecutorSchedulerTest.cancelledRetention(w, false); } finally { w.dispose(); } - w = Schedulers.io().createWorker(); + w = Schedulers.cached().createWorker(); try { ExecutorSchedulerTest.cancelledRetention(w, true); } finally { @@ -82,7 +82,7 @@ public void cancelledTaskRetention() throws InterruptedException { @Test public void workerDisposed() { - Worker w = Schedulers.io().createWorker(); + Worker w = Schedulers.cached().createWorker(); assertFalse(((Disposable)w).isDisposed()); @@ -103,7 +103,7 @@ public void run() { } }; - IoScheduler s = new IoScheduler(); + CachedScheduler s = new CachedScheduler(); s.shutdown(); s.shutdown(); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/FailOnBlockingTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/FailOnBlockingTest.java index 742fc55d2d..8bade06192 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/FailOnBlockingTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/FailOnBlockingTest.java @@ -623,7 +623,7 @@ public void dontfailIOObservableBlockingFirst() { RxJavaPlugins.setFailOnNonBlockingScheduler(true); Observable.just(1) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .map(new Function() { @Override public Integer apply(Integer v) throws Exception { diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerLifecycleTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerLifecycleTest.java index 36452016da..6127aa9f2a 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerLifecycleTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerLifecycleTest.java @@ -82,7 +82,7 @@ public void run() { cd.add(w1); w1.schedule(countAction); - Worker w2 = Schedulers.io().createWorker(); + Worker w2 = Schedulers.cached().createWorker(); cd.add(w2); w2.schedule(countAction); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerTest.java index 7ff340ae22..dcb6e1d91c 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/SchedulerTest.java @@ -219,7 +219,7 @@ public void run() { @Test public void periodicDirectTaskRaceIO() throws Exception { - final Scheduler scheduler = Schedulers.io(); + final Scheduler scheduler = Schedulers.cached(); for (int i = 0; i < 100; i++) { final Disposable d = scheduler.schedulePeriodicallyDirect( @@ -236,7 +236,7 @@ public void periodicDirectTaskRaceIO() throws Exception { public void scheduleDirectThrows() throws Exception { List list = TestHelper.trackPluginErrors(); try { - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { throw new TestException(); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java new file mode 100644 index 0000000000..e5161e0ffb --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.schedulers; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.Scheduler.Worker; +import io.reactivex.rxjava4.disposables.Disposable; +import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.internal.schedulers.DeferredExecutorScheduler; +import io.reactivex.rxjava4.testsupport.SuppressUndeliverable; + +public class VirtualThreadSchedulerTest extends AbstractSchedulerConcurrencyTests { + + @Override + protected Scheduler getScheduler() { + return Schedulers.virtual(); + } + + /** + * IO scheduler defaults to using CachedThreadScheduler. + */ + @Test + public final void virtualScheduler() { + + Flowable f1 = Flowable.just(1, 2, 3, 4, 5); + Flowable f2 = Flowable.just(6, 7, 8, 9, 10); + Flowable f = Flowable.merge(f1, f2).map(new Function() { + + @Override + public String apply(Integer t) { + assertTrue(Thread.currentThread().isVirtual()); + return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); + } + }); + + f.subscribeOn(Schedulers.virtual()).blockingForEach(new Consumer() { + + @Override + public void accept(String t) { + System.out.println("t: " + t); + } + }); + } + + @Test + public final void handledErrorIsNotDeliveredToThreadHandler() throws InterruptedException { + SchedulerTestHelper.handledErrorIsNotDeliveredToThreadHandler(getScheduler()); + } + + @Test + public void cancelledTaskRetention() throws InterruptedException { + Worker w = Schedulers.virtual().createWorker(); + try { + ExecutorSchedulerTest.cancelledRetention(w, false); + } finally { + w.dispose(); + } + w = Schedulers.virtual().createWorker(); + try { + ExecutorSchedulerTest.cancelledRetention(w, true); + } finally { + w.dispose(); + } + } + + @Test + public void workerDisposed() { + Worker w = Schedulers.virtual().createWorker(); + + assertFalse(((Disposable)w).isDisposed()); + + w.dispose(); + + assertTrue(((Disposable)w).isDisposed()); + } + + @Ignore("FIXME DeferredExecutorScheduler doesn't support shutdown yet") + @Test + @SuppressUndeliverable + public void shutdownRejects() { + final int[] calls = { 0 }; + + Runnable r = new Runnable() { + @Override + public void run() { + calls[0]++; + } + }; + + DeferredExecutorScheduler s = new DeferredExecutorScheduler(Executors::newVirtualThreadPerTaskExecutor, true, true); + s.shutdown(); + s.shutdown(); + + s.scheduleDirect(r); + + s.scheduleDirect(r, 1, TimeUnit.SECONDS); + + s.schedulePeriodicallyDirect(r, 1, 1, TimeUnit.SECONDS); + + Worker w = s.createWorker(); + w.dispose(); + + assertEquals(Disposable.disposed(), w.schedule(r)); + + assertEquals(Disposable.disposed(), w.schedule(r, 1, TimeUnit.SECONDS)); + + assertEquals(Disposable.disposed(), w.schedulePeriodically(r, 1, 1, TimeUnit.SECONDS)); + + assertEquals(0, calls[0]); + } +} diff --git a/src/test/java/io/reactivex/rxjava4/single/SingleTest.java b/src/test/java/io/reactivex/rxjava4/single/SingleTest.java index 1172d4eca6..66ff1227a6 100644 --- a/src/test/java/io/reactivex/rxjava4/single/SingleTest.java +++ b/src/test/java/io/reactivex/rxjava4/single/SingleTest.java @@ -160,7 +160,7 @@ public void subscribe(SingleObserver observer) { public void async() { TestSubscriber ts = new TestSubscriber<>(); Single.just("Hello") - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.cached()) .map(new Function() { @Override public String apply(String v) { @@ -212,7 +212,7 @@ public void subscribe(SingleObserver observer) { } observer.onSuccess("success"); } - }).subscribeOn(Schedulers.io()); + }).subscribeOn(Schedulers.cached()); s1.timeout(100, TimeUnit.MILLISECONDS).toFlowable().subscribe(ts); @@ -234,7 +234,7 @@ public void subscribe(SingleObserver observer) { } observer.onSuccess("success"); } - }).subscribeOn(Schedulers.io()); + }).subscribeOn(Schedulers.cached()); s1.timeout(100, TimeUnit.MILLISECONDS, Single.just("hello")).toFlowable().subscribe(ts); diff --git a/src/test/java/io/reactivex/rxjava4/subjects/BehaviorSubjectTest.java b/src/test/java/io/reactivex/rxjava4/subjects/BehaviorSubjectTest.java index 3685fe494e..c4ce29bf68 100644 --- a/src/test/java/io/reactivex/rxjava4/subjects/BehaviorSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava4/subjects/BehaviorSubjectTest.java @@ -365,8 +365,8 @@ public void takeOneSubscriber() { @Test public void emissionSubscriptionRace() throws Exception { - Scheduler s = Schedulers.io(); - Scheduler.Worker worker = Schedulers.io().createWorker(); + Scheduler s = Schedulers.cached(); + Scheduler.Worker worker = Schedulers.cached().createWorker(); try { for (int i = 0; i < 50000; i++) { if (i % 1000 == 0) { @@ -391,7 +391,7 @@ public void run() { final AtomicReference o = new AtomicReference<>(); - rs.subscribeOn(s).observeOn(Schedulers.io()) + rs.subscribeOn(s).observeOn(Schedulers.cached()) .subscribe(new DefaultObserver() { @Override diff --git a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java index 1d7d6398b2..0cafb7c546 100644 --- a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectBoundedConcurrencyTest.java @@ -327,8 +327,8 @@ public void run() { @Test public void replaySubjectEmissionSubscriptionRace() throws Exception { - Scheduler s = Schedulers.io(); - Scheduler.Worker worker = Schedulers.io().createWorker(); + Scheduler s = Schedulers.cached(); + Scheduler.Worker worker = Schedulers.cached().createWorker(); try { for (int i = 0; i < 50000; i++) { if (i % 1000 == 0) { @@ -360,7 +360,7 @@ public void run() { // .doOnSubscribe(v -> System.out.println("!! " + j)) // .doOnNext(e -> System.out.println(">> " + j)) .subscribeOn(s) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) // .doOnNext(e -> System.out.println(">>> " + j)) .subscribe(new DefaultObserver() { diff --git a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java index 699d11163a..ba4b5ee886 100644 --- a/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java +++ b/src/test/java/io/reactivex/rxjava4/subjects/ReplaySubjectConcurrencyTest.java @@ -327,8 +327,8 @@ public void run() { @Test public void replaySubjectEmissionSubscriptionRace() throws Exception { - Scheduler s = Schedulers.io(); - Scheduler.Worker worker = Schedulers.io().createWorker(); + Scheduler s = Schedulers.cached(); + Scheduler.Worker worker = Schedulers.cached().createWorker(); try { for (int i = 0; i < 50000; i++) { if (i % 1000 == 0) { @@ -353,7 +353,7 @@ public void run() { final AtomicReference o = new AtomicReference<>(); - rs.subscribeOn(s).observeOn(Schedulers.io()) + rs.subscribeOn(s).observeOn(Schedulers.cached()) .subscribe(new DefaultObserver() { @Override diff --git a/src/test/java/io/reactivex/rxjava4/subjects/UnicastSubjectTest.java b/src/test/java/io/reactivex/rxjava4/subjects/UnicastSubjectTest.java index 4dd9a7e621..dcdda577e3 100644 --- a/src/test/java/io/reactivex/rxjava4/subjects/UnicastSubjectTest.java +++ b/src/test/java/io/reactivex/rxjava4/subjects/UnicastSubjectTest.java @@ -471,7 +471,7 @@ public void fusedNoConcurrentCleanDueToCancel() { final UnicastSubject us = UnicastSubject.create(); TestObserver to = us - .observeOn(Schedulers.io()) + .observeOn(Schedulers.cached()) .map(Functions.identity()) .observeOn(Schedulers.single()) .firstOrError() diff --git a/src/test/java/io/reactivex/rxjava4/tck/AsyncProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/AsyncProcessorAsPublisherTckTest.java index 096f9e32a0..1265fc392d 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/AsyncProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/AsyncProcessorAsPublisherTckTest.java @@ -30,7 +30,7 @@ public AsyncProcessorAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final AsyncProcessor pp = AsyncProcessor.create(); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/BehaviorProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/BehaviorProcessorAsPublisherTckTest.java index 3edcc0c4fd..7ab9ea7c37 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/BehaviorProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/BehaviorProcessorAsPublisherTckTest.java @@ -31,7 +31,7 @@ public BehaviorProcessorAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final BehaviorProcessor pp = BehaviorProcessor.create(); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/MulticastProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/MulticastProcessorAsPublisherTckTest.java index 48995231fd..5912be3d63 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/MulticastProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/MulticastProcessorAsPublisherTckTest.java @@ -31,7 +31,7 @@ public Publisher createFlowPublisher(final long elements) { final MulticastProcessor mp = MulticastProcessor.create(); mp.start(); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/PublishProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/PublishProcessorAsPublisherTckTest.java index e5caaa15bb..c86be198d2 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/PublishProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/PublishProcessorAsPublisherTckTest.java @@ -30,7 +30,7 @@ public PublishProcessorAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final PublishProcessor pp = PublishProcessor.create(); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java index 56fb44a023..21d0ce4193 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorSizeBoundAsPublisherTckTest.java @@ -30,7 +30,7 @@ public ReplayProcessorSizeBoundAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final ReplayProcessor pp = ReplayProcessor.createWithSize((int)elements + 10); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java index 0c37cf68b8..6874942bb9 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorTimeBoundAsPublisherTckTest.java @@ -32,7 +32,7 @@ public ReplayProcessorTimeBoundAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final ReplayProcessor pp = ReplayProcessor.createWithTime(1, TimeUnit.MINUTES, Schedulers.computation()); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorUnboundedAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorUnboundedAsPublisherTckTest.java index 29dca41c47..fa11458e99 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorUnboundedAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/ReplayProcessorUnboundedAsPublisherTckTest.java @@ -30,7 +30,7 @@ public ReplayProcessorUnboundedAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final ReplayProcessor pp = ReplayProcessor.create(); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); diff --git a/src/test/java/io/reactivex/rxjava4/tck/UnicastProcessorAsPublisherTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/UnicastProcessorAsPublisherTckTest.java index 5d098c47af..e144f1add9 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/UnicastProcessorAsPublisherTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/UnicastProcessorAsPublisherTckTest.java @@ -30,7 +30,7 @@ public UnicastProcessorAsPublisherTckTest() { public Publisher createFlowPublisher(final long elements) { final UnicastProcessor pp = UnicastProcessor.create(); - Schedulers.io().scheduleDirect(new Runnable() { + Schedulers.cached().scheduleDirect(new Runnable() { @Override public void run() { long start = System.currentTimeMillis();