我有点麻烦了解subscribeOn / observeOn如何在RxJava中工作。 我创建了一个带有observable的简单应用程序,可以发出太阳系行星名称,进行一些映射和过滤并打印结果。

据我所知,调度工作到后台线程是通过subscribeOn运算符完成的(它似乎工作正常)。

使用observeOn运算符观察后台线程也可以正常工作。

但是我在理解方面遇到了麻烦,如何在调用线程上观察(无论是主线程还是其他任何线程)。 使用AndroidSchedulers.mainThread()运算符可以在Android上轻松完成,但我不知道如何在纯java中实现这一点。

这是我的代码:

public class Main {

    public static void main(String[] args) throws InterruptedException {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 3000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());

        System.out.println("Main thread: " + getCurrentThreadInfo());

        Observable<String> stringObservable = Observable.from(Arrays.asList("Merkury", "Wenus", "Ziemia", "Mars", "Jowisz", "Saturn", "Uran", "Neptun", "Pluton"))
                .map(in -> {
                    System.out.println("map on: " + getCurrentThreadInfo());
                    return in.toUpperCase();
                })
                .filter(in -> {
                    System.out.println("filter on: " + getCurrentThreadInfo());
                    return in.contains("A");
                })
                .subscribeOn(Schedulers.from(executor));

        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread("Thread-" + i) {
                @Override
                public void run() {
                    stringObservable
                            .buffer(5)
                            .subscribe(s -> System.out.println("Result " + s + " on: " + getCurrentThreadInfo()));
                }
            };
            thread.start();
        }

    }

    private static String getCurrentThreadInfo() {
        return Thread.currentThread().getName() + "(" + Thread.currentThread().getId() + ")";
    }
}

创建和工作中​​的Observable在执行者的三个线程中的一个上订阅。 这按预期工作。 但是如何在for循环中观察那些动态创建的线程的结果呢? 有没有办法从当前线程创建调度程序?

另外,我发现在运行此代码后,它永远不会终止,我不知道为什么? :(

#1楼 票数:80 已采纳

要回答你的问题,让我从头开始,这可以让其他人了解你已经知道的事情。

调度程序

调度程序与Executors for Java扮演相同的角色。 简而言之 - 他们决定执行哪些线程操作。

通常,Observable和运算符在当前线程中执行。 有时您可以将Scheduler作为参数传递给Observable或operator(例如Observable.timer())。

另外,RxJava提供了2个运算符来指定调度程序:

  • subscribeOn - 指定Observable将在其上运行的Scheduler
  • observeOn - 指定观察者将观察此Observable的Scheduler

为了快速理解它们,我使用了一个示例代码:

在所有示例中,我将使用helper createObservable,它发出Observable操作的线程的名称:

 public static Observable<String> createObservable(){
        return Observable.create((Subscriber<? super String> subscriber) -> {
                subscriber.onNext(Thread.currentThread().getName());
                subscriber.onCompleted();
            }
        );
    }

没有调度程序:

createObservable().subscribe(message -> {
        System.out.println("Case 1 Observable thread " + message);
        System.out.println("Case 1 Observer thread " + Thread.currentThread().getName());
    });
    //will print:
    //Case 1 Observable thread main
    //Case 1 Observer thread main

SubscribeOn:

createObservable()
            .subscribeOn(Schedulers.newThread())
            .subscribe(message -> {
                System.out.println("Case 2 Observable thread " + message);
                System.out.println("Case 2 Observer thread " + Thread.currentThread().getName());
            });
            //will print:
            //Case 2 Observable thread RxNewThreadScheduler-1
            //Case 2 Observer thread RxNewThreadScheduler-1

SubscribeOn和ObserveOn:

reateObservable()
            .subscribeOn(Schedulers.newThread())
            .observeOn(Schedulers.newThread())
            .subscribe(message -> {
                System.out.println("Case 3 Observable thread " + message);
                System.out.println("Case 3 Observer thread " + Thread.currentThread().getName());
            });
            //will print:
            //Case 3 Observable thread RxNewThreadScheduler-2
            //Case 3 Observer thread RxNewThreadScheduler-1

ObserveOn:

createObservable()
            .observeOn(Schedulers.newThread())
            .subscribe(message -> {
                System.out.println("Case 4 Observable thread " + message);
                System.out.println("Case 4 Observer thread " + Thread.currentThread().getName());
            });
            //will print:
            //Case 4 Observable thread main
            //Case 4 Observer thread RxNewThreadScheduler-1

回答:

AndroidSchedulers.mainThread()返回一个sheduler,它将工作委托给与主线程关联的MessageQueue。
为此,它使用android.os.Looper.getMainLooper()和android.os.Handler。

换句话说,如果要指定特定线程,则必须提供在线程上计划和执行任务的方法。

在它下面可以使用任何类型的MQ来存储循环Quee和执行任务的任务和逻辑。

在java中,我们有Executor,它被指定用于这样的任务。 RxJava可以从这样的Executor轻松创建Scheduler。

下面的示例显示了如何在主线程上观察(不是特别有用但显示所有必需的部分)。

public class RunCurrentThread implements Executor {

    private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();

    public static void main(String[] args) throws InterruptedException {
        RunCurrentThread sample = new RunCurrentThread();
        sample.observerOnMain();
        sample.runLoop();
    }

    private void observerOnMain() {
        createObservable()
                .subscribeOn(Schedulers.newThread())
                .observeOn(Schedulers.from(this))
                .subscribe(message -> {
                    System.out.println("Observable thread " + message);
                    System.out.println("Observer thread " + Thread.currentThread().getName());
                });
        ;
    }

    public Observable<String> createObservable() {
        return Observable.create((Subscriber<? super String> subscriber) -> {
                    subscriber.onNext(Thread.currentThread().getName());
                    subscriber.onCompleted();
                }
        );
    }

    private void runLoop() throws InterruptedException {
        while(!Thread.interrupted()){
            tasks.take().run();
        }
    }

    @Override
    public void execute(Runnable command) {
        tasks.add(command);
    }
}

最后一个问题,为什么你的代码没有终止:

ThreadPoolExecutor通过defult使用非deamon线程,因此您的程序在它们存在之前不会结束。 您应该使用shutdown方法关闭线程。

#2楼 票数:7

这是为RxJava 2更新的简化示例。它与Marek的答案相同:Executor将runnable添加到正在调用者线程上使用的BlockingQueue。

public class ThreadTest {

    @Test
    public void test() throws InterruptedException {

        final BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();

        System.out.println("Caller thread: " + Thread.currentThread().getName());

        Observable.fromCallable(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("Observable thread: " + Thread.currentThread().getName());
                return 1;
            }
        })
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.from(new Executor() {
                @Override
                public void execute(@NonNull Runnable runnable) {
                    tasks.add(runnable);
                }
            }))
            .subscribe(new Consumer<Integer>() {
                @Override
                public void accept(@NonNull Integer integer) throws Exception {
                    System.out.println("Observer thread: " + Thread.currentThread().getName());
                }
            });
        tasks.take().run();
    }

}

// Output: 
// Caller thread main
// Observable thread RxCachedThreadScheduler-1
// Observer thread main

  ask by Filip Zymek translate from so

未解决问题?本站智能推荐:

1回复

为什么我的RxJava可观察不会触发订阅者?

我正在搞乱RxJava,我想要传输一千个连续的整数。 然后我想异步将它们分成奇数和偶数流,然后异步打印它们。 但是,我没有打印出任何内容或至少非常部分的输出。 我错过了什么? 我的安排不正确吗? 或者控制台是否在Eclipse中存在多线程问题?
1回复

RxJava调度程序 - 线程行为和饥饿?

我有一个带有observeOn()和subscribeOn()的double-take。 我知道他们没有在单个流上并行排放。 换句话说,单一的排放流只能放在一个线程上吗? 我的测试似乎表明了这一点。 我的理解是你必须使用flatMap()调度程序,如.flatMap(v -> Ob
2回复

仅使用单个线程时如何在RxJava中递归?

我在基于RxJava的网络堆栈中有一些工作的递归代码,用于将HTTP主体字符串文件列表映射到表示该文件的自定义POJO的Observable中。 但是,我使用的是.scheduleOn(Schedulers.newThread()) ,它使用多个新线程来完成工作。 我只是发现我需要连接的
1回复

使用多线程RxJava进行反应性拉动

我正在尝试在RxJava中构建一个反应式拉动观察器 。 我的观察者是这样的: 我想在4个并发批处理(缓冲区)中处理它,如下所示: 然后,我需要以不同的大小批量处理结果,如下所示: 问题是,该命令可观察处理一次全部 ,而我希望在需要的时候它们进行处理。 以下是发
1回复

间隔调度的RxJava可观察对象花费的时间比指定时间更长

在以下代码中,可观察对象应该每300毫秒触发一次。 我通过模拟耗时1秒的背景活动来提高效果。 我期待着,因为我正在使用在下面使用线程池的调度程序,因此可观察到的间隔将每300毫秒不断触发一个新线程。 而是发生的是,可观察到的间隔每次等待一整秒,然后再次触发。 这是理想的行为吗? 如果一
2回复

RxJava - 按顺序上传文件 - 当onNext调用时,发出下一个项目

我有一种方法可以将多个文件同时上传到云存储。 它看起来像这样: 这个输出是: 我希望它按顺序工作,例如: 用Rx做这样的事情有可能吗? 编辑 用concatMap替换第一个flatMap concatMap完成了这项工作。 我以为我知道这些运算符之间的区别
2回复

如何使多线程观察者计算速率适应冷的Observable >

我有一个Source作为冷Observable<List<T>> ,它以块(列表)形式发射元素,我想在单独的线程中处理块中的每个项目,而发射器(源)正在等待终止处理发出的块中的所有项目都将继续进行下一个,依此类推。 这段代码(rxjava 2.0.6)仅在一个线程中
3回复

RxJava:如何从Observable获取所有结果和错误

我正在从事涉及Hystrix的项目,因此决定使用RxJava。 现在,将剩下的事情忘给Hystrix,因为我认为主要问题是我完全搞砸了正确编写Observable代码的问题。 需要:我需要一种返回表示多个可观察对象的可观察对象的方法,每个可观察对象都运行一个用户任务。 我希望Obser