具有多个订阅者和事件的RxJava并发

时间:2016-11-06 09:25:24

标签: java multithreading concurrency rx-java

我正在寻找一种方法将多个订阅者附加到RxJava Observable流,每个订阅者异步处理发出的事件。

我首先尝试使用.flatMap(),但这似乎并不适用于任何后续订阅者。所有订阅者都在同一个线程上处理事件。

.flatMap(s -> Observable.just(s).subscribeOn(Schedulers.newThread()))

最终工作的是通过每次创建一个新的Observable来消耗新线程中的每个事件:

Observable.from(Arrays.asList(new String[]{"1", "2", "3"}))
            .subscribe(j -> {
                Observable.just(j)
                        .subscribeOn(Schedulers.newThread())
                        .subscribe(i -> {
                            try {
                                Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + i);
                        });
            });

输出:

s1=>RxNewThreadScheduler-1=>1
s1=>RxNewThreadScheduler-2=>2
s1=>RxNewThreadScheduler-3=>3

最终结果是多个订阅者:

ConnectableObservable<String> e = Observable.from(Arrays.asList(new String[]{"1", "2", "3"}))
            .publish();

    e.subscribe(j -> {
        Observable.just(j)
                .subscribeOn(Schedulers.newThread())
                .subscribe(i -> {
                    try {
                        Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + i);
                });
    });

    e.subscribe(j -> {
        Observable.just(j)
                .subscribeOn(Schedulers.newThread())
                .subscribe(i -> {
                    try {
                        Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("s2=>" + Thread.currentThread().getName() + "=>" + i);
                });
    });

    e.connect();

输出:

s2=>RxNewThreadScheduler-4=>2
s1=>RxNewThreadScheduler-1=>1
s1=>RxNewThreadScheduler-3=>2
s2=>RxNewThreadScheduler-6=>3
s2=>RxNewThreadScheduler-2=>1
s1=>RxNewThreadScheduler-5=>3

然而,这看起来有点笨重。是否有一个更优雅的解决方案或者RxJava不是一个很好的用例呢?

4 个答案:

答案 0 :(得分:0)

使用.flatMap(s -> Observable.just(s).observeOn(Schedulers.newThread())....)

答案 1 :(得分:0)

如果我正确地理解了rx-contract,那么你正试图做一些与之相反的事情。

让我们看一下合约

RxJava Observable的合约是事件(onNext(),onCompleted(),onEr ror())永远不会同时发出。换句话说,一个Observable stream必须始终序列化并且是线程安全的。每个事件都可以从a发出 不同的线程,只要排放不并发。这意味着没有 inter- 离开或同时执行onNext()。如果仍在执行onNext() 一个线程,另一个线程无法再次开始调用它(交错)。 --Tomasz Nurkiewicz在Reactive Programming with RxJava

在我看来,您试图通过在外部订阅中使用嵌套订阅来破解合同。对订阅者的onNext调用不再被序列化。

为什么不将&#34; async&#34; -workload从订阅者移动到flatMap-operator并订阅新的observable:

    ConnectableObservable<String> stringObservable = Observable.from(Arrays.asList(new String[]{"1", "2", "3"}))
            .flatMap(s -> {
                return Observable.just(s).subscribeOn(Schedulers.computation());
            })
            .publish();

    stringObservable
            .flatMap(s -> {
                // do More asyncStuff depending on subscription
                return Observable.just(s).subscribeOn(Schedulers.newThread());
            })
            .subscribe(s -> {
                // use result here
            });

    stringObservable
            .subscribe(s -> {
                // use immediate result here.
            });

    stringObservable.connect();

答案 2 :(得分:0)

flatMap内的doOnNext上的Observable以及flatMap将产生与您相同的输出。

onNext()始终以顺序方式调用,因此在doOnNext之后使用flatMap也不会对您有用。由于同样的原因,在最终的subscribe中写入操作在您的情况下不起作用。

以下代码是使用RxJava2编写的。在RxJava的第1版中,您必须在try-catch周围添加Thread.sleep块。

ConnectableObservable<String> e = Observable.just("1", "2", "3").publish();

e.flatMap(
      s -> Observable.just(s)
          .subscribeOn(Schedulers.newThread())
          .doOnNext(i -> {  // <<<<<<
              Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
              System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + i);
          }))
  .subscribe();

e.flatMap(
      s -> Observable.just(s)
          .subscribeOn(Schedulers.newThread())
          .doOnNext(i -> {  // <<<<<<
              Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
              System.out.println("s2=>" + Thread.currentThread().getName() + "=>" + i);
          }))
  .subscribe();

e.connect();

答案 3 :(得分:0)

您可以使用Flowable和parallel实现它

        Flowable.fromIterable(Arrays.asList("1", "2", "3"))
                .parallel(3)
                .runOn(Schedulers.newThread())
                .map(item -> {
                    try {
                        Thread.sleep(ThreadLocalRandom.current().nextInt(100, 500));
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("s1=>" + Thread.currentThread().getName() + "=>" + item);

                    return Completable.complete();
                })
        .sequential().subscribe();