将可观察对象合并到一个可观察对象时,是否可观察doOnNext线程安全

时间:2019-01-10 15:11:54

标签: thread-safety observable rx-java2

我有一个Observable列表,每个Observable都已订阅在一个池线程调度程序上,我将Observable列表合并为一个Observable Observable.merge(observables)。合并结果可观察到的doOnNext方法是否是线程安全的?代码示例如下。

    ThreadFactory threadFactory = new ThreadFactoryBuilder()
            .setDaemon(true)
            .setNameFormat("pooled-%s")
            .build();
    ExecutorService executorService = Executors.newCachedThreadPool(threadFactory);
    List<Observable<String>> observableList = Stream.of("1", "2", "3", "4")
            .map(o -> {
                        Observable<String> ob = Observable.create(
                                emitter -> {
                                    Thread.sleep(new Random().nextInt(50));
                                    System.out.println("emitter:" + o + " Thread:" + Thread.currentThread().getName());
                                    emitter.onNext(o);
                                    emitter.onComplete();
                                });
                        return ob.subscribeOn(Schedulers.from(executorService));
                    }
            ).collect(Collectors.toList());

    List<String> result = new ArrayList<>(); //is need thread safe list here ?

    Observable.merge(observableList)
            .doOnNext(e -> {
                Thread.sleep(new Random().nextInt(50));
                System.out.println("doOnNext:" + e + " Thread:" + Thread.currentThread().getName());
                result.add(e);
            })
            .blockingLast();

情况1: 当我运行输出时,似乎是信号线程调用了doOnNext。

    emitter:2 Thread:pooled-1
    emitter:3 Thread:pooled-2
    emitter:4 Thread:pooled-3
    emitter:1 Thread:pooled-0
    doOnNext:2 Thread:pooled-1
    doOnNext:1 Thread:pooled-1
    doOnNext:3 Thread:pooled-1
    doOnNext:4 Thread:pooled-1

情况2: 当我逐步调试时,输出改变了,似乎由多线程调用了doOnNext。

    emitter:1 Thread:pooled-0
    doOnNext:1 Thread:pooled-0
    emitter:4 Thread:pooled-3
    emitter:3 Thread:pooled-2
    emitter:2 Thread:pooled-1
    doOnNext:4 Thread:pooled-3
    doOnNext:2 Thread:pooled-3
    doOnNext:3 Thread:pooled-3

我很困惑。

  1. 我没有看到任何代码可以在发射器和doOnNext之间切换线程,所以如果我错过了相同的代码,为什么会出现“情况1”。
  2. 在这种情况下,doOnNext是否不安全,结果列表应使用线程安全列表。
  3. 在这种情况下,内部使用ArrayList的Observable.toList方法内部存在并发问题。

1 个答案:

答案 0 :(得分:0)

流是顺序的,并保证在操作符中不重叠,尤其是在组合/协调操作符中。但是,这并不排除线程之间发生doOnNext“跳跃”。如果要确保doOnNext始终在同一线程上运行,请在其之前使用observeOn

  

我没有看到任何代码可以在发射器和doOnNext之间切换线程,所以如果我错过了相同的代码,为什么会出现“情况1”。

流可以从任意数量的线程中驱动merge并推动它。

  

在这种情况下,doOnNext是否不安全,结果列表应使用线程安全列表。

doOnNext在输入参数和执行方面是线程安全的。如果您的回调是有状态的或捕获了全局状态,则多个流实现可能会发生冲突。这些必须通过外部方式进行同步。

  

内部使用ArrayList的Observable.toList方法在这种情况下存在并发问题。

toList保证不会重叠驱动,并且其内部ArrayList是针对每个订户的,因此不存在并发问题。

相关问题