我再次将RxJava与Java 9 Flow进行比较。我看到Flow默认是异步的,我想知道是否有办法让它同步运行。
有时我们只是想将它用于Nio而不是糖语法,并且具有更加同质的代码。
默认情况下,在RxJava中它是同步的,您可以使用管道中的observerOn
和subscribeOn
异步运行它。
Flow中是否有任何操作符使其在主线程中运行?。
问候。
答案 0 :(得分:4)
您可以按照 Flow
中的说明定义自定义Publisher
,以便使用同步执行。
一个非常简单的发布商,只发布(如果需要)一个 对单个订户的真实项目。因为订户只收到 单个项目,此类不使用缓冲和排序控制。
class OneShotPublisher implements Publisher<Boolean> {
private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based
private boolean subscribed; // true after first subscribe
public synchronized void subscribe(Subscriber<? super Boolean> subscriber) {
if (subscribed)
subscriber.onError(new IllegalStateException()); // only one allowed
else {
subscribed = true;
subscriber.onSubscribe(new OneShotSubscription(subscriber, executor));
}
}
static class OneShotSubscription implements Subscription {
private final Subscriber<? super Boolean> subscriber;
private final ExecutorService executor;
private Future<?> future; // to allow cancellation
private boolean completed;
OneShotSubscription(Subscriber<? super Boolean> subscriber,
ExecutorService executor) {
this.subscriber = subscriber;
this.executor = executor;
}
public synchronized void request(long n) {
if (n != 0 && !completed) {
completed = true;
if (n < 0) {
IllegalArgumentException ex = new IllegalArgumentException();
executor.execute(() -> subscriber.onError(ex));
} else {
future = executor.submit(() -> {
subscriber.onNext(Boolean.TRUE);
subscriber.onComplete();
});
}
}
}
public synchronized void cancel() {
completed = true;
if (future != null) future.cancel(false);
}
}
}
答案 1 :(得分:3)
没有操作员这样做,但API允许您控制项目的发布方式。因此,您可以直接从当前线程调用订阅者方法。
class SynchronousPublisher implements Publisher<Data> {
public synchronized void subscribe(Subscriber<? super Data> subscriber) {
subscriber.onSubscribe(new SynchronousSubscription(subscriber));
}
}
static class SynchronousSubscription implements Subscription {
private final Subscriber<? super Data> subscriber;
SynchronousSubscription(Subscriber<? super Data> subscriber) {
this.subscriber = subscriber;
}
public synchronized void request(long n) {
... // prepare item
subscriber.onNext(someItem);
}
...
}
}
答案 2 :(得分:2)
这取决于你在主线程上运行的意思。
如果要强制在特定线程上执行任意Flow,则没有标准方法可以执行此操作,除非在库中实现Flow,您可以覆盖提供异步的部分。在RxJava术语中,这些是Scheduler
实用程序类提供的Schedulers
。
如果要在主线程上观察Flow,则必须在阻塞线程的Flow.Subscriber
之上编写阻塞队列使用者,直到队列中有项目为止。这可能会变得复杂,因此我将向您推荐Reactive4JavaFlow中的blockingSubscribe
实现。
如果要将Java主线程用作Executor
/ Scheduler
,那就更复杂了,需要类似的阻塞机制以及来自线程池执行器的一些想法。 Reactive4JavaFlow碰巧有这样的调度程序,您可以通过new SubmissionPublisher<>(128, blockingScheduler::schedule)
将其用作执行程序。