Java 9 Flow SubmissionPublisher提供方法的行为

时间:2017-09-30 11:15:43

标签: java java-9 reactive-streams java-flow

我一直在玩Java Flow offer运算符,但是在阅读完文档并完成我的测试后我才明白。

这是我的测试

@Test
public void offer() throws InterruptedException {
    //Create Publisher for expected items Strings
    SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
    //Register Subscriber
    publisher.subscribe(new CustomSubscriber<>());
    publisher.subscribe(new CustomSubscriber<>());
    publisher.subscribe(new CustomSubscriber<>());
    publisher.offer("item", (subscriber, value) -> false);
    Thread.sleep(500);
}

要约运算符接收要发出的项目和BiPredicate函数,据我所知阅读文档,只有在谓词函数为真的情况下才会发出它。

Bur通过测试后结果是

Subscription done:
Subscription done:
Subscription done:
Got : item --> onNext() callback
Got : item --> onNext() callback
Got : item --> onNext() callback

结果没有变化,如果不是假,我返回true。

任何人都可以更好地向我解释这个算子。

2 个答案:

答案 0 :(得分:5)

不,谓词函数用于决定是否重试发布操作,如docs中所述:

  

onDrop - 如果为非null,则处理程序在使用订阅者和项目的参数下降到订阅者时调用;如果它返回true,则重新尝试(一次)

它不会影响该项目是否最初发送。

编辑:使用offer方法时出现下降的示例

我想出了一个示例,说明在调用offer方法时如何发生丢弃。我不认为输出是100%确定性的,但是当它运行几次时有明显的区别。您可以只更改处理程序以返回true而不是false,以查看重试如何减少饱和缓冲区导致的丢弃。在此示例中,通常会发生丢弃,因为最大缓冲区容量明显很小(传递给SubmissionPublisher的构造函数)。但是在小睡眠期后启用重试时,会删除掉落:

public class SubmissionPubliserDropTest {

    public static void main(String[] args) throws InterruptedException {
        // Create Publisher for expected items Strings
        // Note the small buffer max capacity to be able to cause drops
        SubmissionPublisher<String> publisher =
                               new SubmissionPublisher<>(ForkJoinPool.commonPool(), 2);
        // Register Subscriber
        publisher.subscribe(new CustomSubscriber<>());
        publisher.subscribe(new CustomSubscriber<>());
        publisher.subscribe(new CustomSubscriber<>());
        // publish 3 items for each subscriber
        for(int i = 0; i < 3; i++) {
            int result = publisher.offer("item" + i, (subscriber, value) -> {
                // sleep for a small period before deciding whether to retry or not
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return false;  // you can switch to true to see that drops are reduced
            });
            // show the number of dropped items
            if(result < 0) {
                System.err.println("dropped: " + result);
            }
        }
        Thread.sleep(3000);
        publisher.close();
    }
}

class CustomSubscriber<T> implements Flow.Subscriber<T> {

    private Subscription sub;

    @Override
    public void onComplete() {
        System.out.println("onComplete");
    }

    @Override
    public void onError(Throwable th) {
        th.printStackTrace();
        sub.cancel();
    }

    @Override
    public void onNext(T arg0) {
        System.out.println("Got : " + arg0 + " --> onNext() callback");
        sub.request(1);
    }

    @Override
    public void onSubscribe(Subscription sub) {
        System.out.println("Subscription done");
        this.sub = sub;
        sub.request(1);
    }

}

答案 1 :(得分:3)

SubmissionPublisher.offer 声明

  

如果资源限制,该项目可能会被一个或多个订阅者删除   超出,在这种情况下给定的处理程序(如果非null)   调用,如果它返回true,则重试一次。

只需理解,在两个电话中

publisher.offer("item", (subscriber, value) -> true); // the handler would be invoked

publisher.offer("item", (subscriber, value) -> false); // the handler wouldn't be invoked

publisher仍然会将当前订阅者发布给定项目。 ,这会在您当前的情景中发生。

用于验证您提供的处理程序是否通过尝试重现而被调用的方案在资源限制方面很难,正如文档建议的那样:

  

如果资源限制,该项目可能会被一个或多个订阅者删除   超出,在这种情况下给定的处理程序(如果非null)是   调用,如果返回true,则重试一次。

然而,您可以尝试使用设置为基本最小值的项目删除项目 offer​(T item, long timeout, TimeUnit unit, BiPredicate<Flow.Subscriber<? super T>,? super T> onDrop)

的重载方法
  

timeout - 之前等待任何订阅者资源的时间   放弃,以单位为单位

     

unit - 确定如何的TimeUnit   解释超时参数

由于offer方法可能会丢弃项目(立即或使用 有界超时 ),这将提供插入处理程序然后重试的机会。