RxJava .subscribeOn(Schedulers.newThread())问题

时间:2015-06-11 21:37:15

标签: java rx-java

我在普通的JDK 8上。我有这个简单的RxJava示例:

Observable
.from(Arrays.asList("one", "two", "three"))
.doOnNext(word -> System.out.printf("%s uses thread %s%n", word, Thread.currentThread().getName()))
//.subscribeOn(Schedulers.newThread())
.subscribe(word -> System.out.println(word));

并且它逐行打印出单词,与线程的信息交织在一起,这是主要的'对于所有下一个电话,正如预期的那样。

但是,当我取消注释subscribeOn(Schedulers.newThread())电话时,根本不会打印任何内容。为什么它不起作用?我希望它为每个onNext()调用启动一个新线程,并doOnNext()打印该线程的名称。现在,我也没有看到任何其他调度程序。

当我在main的末尾添加对Thread.sleep(10000L)的调用时,我可以看到输出,这表明RxJava使用的线程都是守护进程。是这样的吗?可以以某种方式更改,但使用自定义ThreadFactory或类似的概念,而不必实现自定义调度程序?

通过上述更改,线程名称始终为RxNewThreadScheduler-1,而newThread的文档为" Scheduler为每个工作单元创建一个新的{@link Thread}"。是不是应该为所有排放创建一个新线程?

3 个答案:

答案 0 :(得分:6)

正如Vladimir所提到的,RxJava标准调度程序在守护程序线程上运行,后者在您的示例中终止,因为主线程退出。我想强调的是,他们没有在新线程上安排每个值,但是他们在新创建的线程上为每个订阅者安排值流。第二次订阅会给你“RxNewThreadScheduler-2”。

您实际上不需要更改默认调度程序,只需使用Schedulers.from()包装您自己的基于Executor的调度程序,并将其作为参数提供给所需的:

ThreadPoolExecutor exec = new ThreadPoolExecutor(
        0, 64, 2, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
exec.allowCoreThreadTimeOut(true);

Scheduler s = Schedulers.from(exec);

Observable
.from(Arrays.asList("one", "two", "three"))
.doOnNext(word -> System.out.printf("%s uses thread %s%n", word,
    Thread.currentThread().getName()))
.subscribeOn(s)
.subscribe(word -> System.out.println(word));

我有一系列关于RxJava调度程序的blog posts,它们可以帮助您实现“更永久”的变体。

答案 1 :(得分:0)

与新人的看法相反,反应流不是固有并发的,而是固有异步的。它们本质上也是顺序的,并且必须在流中配置并发。简而言之,反应流在其末端自然是顺序的,但在其核心可以并发

秘密之处在于在流中使用 flatMap()运算符。该运算符从源流中获取一个 Observable 输入,并在内部将其重新发送为它也订阅的 Observable > 流< strong>一次所有实例。只要 flatMap()内部流在多线程上下文中执行,它就会同时执行所提供的Function ,该函数将应用您的逻辑,最后重新发送结果在原始流上,因为它是自己的排放。

这听起来很复杂(乍看之下很多),但是带有解释的简单示例有助于理解这一概念。

从类似的问题here和有关RxJava2 SchedulersConcurrency的文章中找到更多详细信息,并提供代码示例以及有关如何依次和同时使用Scheduler的详细说明。

希望这会有所帮助,

Softjake

答案 2 :(得分:0)

public class MainClass {

    public static void main(String[] args) {

        Scheduler scheduler = Schedulers.from(Executors.newFixedThreadPool(10, Executors.defaultThreadFactory()));

        Observable.interval(1,TimeUnit.SECONDS)
                .doOnNext(word -> System.out.printf("%s uses thread %s%n", word,
                        Thread.currentThread().getName()))
                .subscribeOn(scheduler)
                .observeOn(Schedulers.io())
                .doOnNext(word -> System.out.printf("%s uses thread %s%n", word,
                        Thread.currentThread().getName()))
                .subscribe();
    }

}