Java 9反应流:一个订阅服务器是否属于一个发布服务器

时间:2019-03-20 17:36:32

标签: java reactive-programming java-9 reactive

我想知道被动流发布者是否可以安全地假设订阅仅属于它 ,并且如果发布者即将退出使用(例如被关闭),请致电java.util.concurrent.Flow.Subscriber#onComplete 。下面的代码示例演示了难题(显然,这只是一些综合代码来演示问题):

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Flow;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TimePublisher implements Flow.Publisher<Long> {

    private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);

    private final ConcurrentLinkedQueue<Flow.Subscriber<? super Long>> subscribersList = new ConcurrentLinkedQueue<>();


    private TimePublisher() {

    }

    public static TimePublisher newInstance() {
        TimePublisher timePublisher = new TimePublisher();
        timePublisher.startTickScheduler();

        return timePublisher;
    }

    private void startTickScheduler() {
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            // does not make too much sense: just for the sake of the example
            final long currentTimeMillis = System.currentTimeMillis();
            subscribersList.forEach(sub -> sub.onNext(currentTimeMillis));
        }, 1, 1, TimeUnit.SECONDS);
    }

    @Override
    public void subscribe(Flow.Subscriber<? super Long> subscriber) {

        subscribersList.add(subscriber);

        subscriber.onSubscribe(new Flow.Subscription() {
            @Override
            public void request(long n) {
                // no-op in this sample
            }

            @Override
            public void cancel() {
                subscribersList.remove(subscriber);
            }
        });
    }

    public void stop() {
        // the publisher can be stopped from the outside: after that it will
        // definitely not emit any next items.
        scheduledExecutorService.shutdown();

        // QUESTION: can we assume that a Subscriber is subscribed to only this Publisher?
        // if it is subscribed to another publisher, the following is illegal, as onNext
        // could potentially be called by another Publisher...
        subscribersList.forEach(Flow.Subscriber::onComplete);

        subscribersList.clear();
    }
}
  • 在调用TimePublisher#stop时,该特定的发布者将绝对不会发出任何onNext调用,因此调用onComplete似乎是合理的选择
  • 但是,如果订阅者也订阅了另一个发布者,则调用onComplete可能是非法的,因为另一个发布者可能仍在发出项目。

1 个答案:

答案 0 :(得分:3)

Subscriber的文档中说

  

对于每个Flow.Subscription ,该接口中的方法均按严格的顺序调用。

onComplete,尤其是:

  

在已知不会因错误终止的订阅不会发生其他订阅者方法调用的情况下调用

方法,此后,订阅不会调用其他订阅者方法。如果此方法引发异常,则导致的行为是不确定的。

因此其他Subscription继续调用方法是合法的。

Flow文档说,在Subscription实现中可以有多个Subscriber,但不建议这样做:

  

由于给定Flow的Subscriber方法调用是严格排序的,因此除非这些Subscriber维护多个Subscriptions(在这种情况下最好定义多个Subscriber,最好使用多个Subscriber,否则不需要使用这些方法来使用锁或volatile)自己的订阅)。