简体   繁体   English

RxJava观察调用/订阅线程

[英]RxJava Observing on calling/subscribing thread

I have some trouble understandig how subscribeOn/observeOn works in RxJava. 我有点麻烦了解subscribeOn / observeOn如何在RxJava中工作。 I've created simple app with observable that emits solar system planet names, does some mapping and filtering and prints results. 我创建了一个带有observable的简单应用程序,可以发出太阳系行星名称,进行一些映射和过滤并打印结果。

As I understand, scheduling work to background thread is done via subscribeOn operator (and it seems to work fine). 据我所知,调度工作到后台线程是通过subscribeOn运算符完成的(它似乎工作正常)。

Observing on background thread also works fine with observeOn operator. 使用observeOn运算符观察后台线程也可以正常工作。

But I have trouble in understanding, how to observe on calling thread (either if it is main thread or any other). 但是我在理解方面遇到了麻烦,如何在调用线程上观察(无论是主线程还是其他任何线程)。 It is easily done on Android with AndroidSchedulers.mainThread() operator, but I don't know how to achieve this in pure java. 使用AndroidSchedulers.mainThread()运算符可以在Android上轻松完成,但我不知道如何在纯java中实现这一点。

Here's my code: 这是我的代码:

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 in created and work is subscribed on one of three thread from executor. 创建和工作中​​的Observable在执行者的三个线程中的一个上订阅。 This works as expected. 这按预期工作。 But how to observe results on those dynamically created thread in for loop? 但是如何在for循环中观察那些动态创建的线程的结果呢? Is there a way to create Scheduler from current thread? 有没有办法从当前线程创建调度程序?

Also, I've found out that after running this code, it never terminates and I don't know why? 另外,我发现在运行此代码后,它永远不会终止,我不知道为什么? :( :(

To answer your question, let me start from beginning, this allows other people to understand what you already know. 要回答你的问题,让我从头开始,这可以让其他人了解你已经知道的事情。

Schedulers 调度程序

Schedulers play the same role as Executors for Java. 调度程序与Executors for Java扮演相同的角色。 Briefly - they decide on which thread actions are executed. 简而言之 - 他们决定执行哪些线程操作。

Usually an Observable and operators execute in current thread. 通常,Observable和运算符在当前线程中执行。 Sometimes you can pass Scheduler to Observable or operator as a parameter (eg Observable.timer()). 有时您可以将Scheduler作为参数传递给Observable或operator(例如Observable.timer())。

Additionally RxJava provides 2 operators to specify Scheduler: 另外,RxJava提供了2个运算符来指定调度程序:

  • subscribeOn - specify the Scheduler on which an Observable will operate subscribeOn - 指定Observable将在其上运行的Scheduler
  • observeOn - specify the Scheduler on which an observer will observe this Observable observeOn - 指定观察者将观察此Observable的Scheduler

To understand them quickly, I use a the example code: 为了快速理解它们,我使用了一个示例代码:

On all samples, I will use helper createObservable, which emits a name of thread on which the Observable operates: 在所有示例中,我将使用helper createObservable,它发出Observable操作的线程的名称:

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

Without schedulers: 没有调度程序:

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: 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 and ObserveOn: 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: 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

Answer: 回答:

AndroidSchedulers.mainThread() returns a sheduler which delegates work to MessageQueue associated with main thread. AndroidSchedulers.mainThread()返回一个sheduler,它将工作委托给与主线程关联的MessageQueue。
For this purpose it uses android.os.Looper.getMainLooper() and android.os.Handler. 为此,它使用android.os.Looper.getMainLooper()和android.os.Handler。

In other words, if you would like to specify particular thread, you must provide means to schedule and perform tasks on thread. 换句话说,如果要指定特定线程,则必须提供在线程上计划和执行任务的方法。

Underneath it may use any kind of MQ for storing tasks and logic which loops the Quee and execute tasks. 在它下面可以使用任何类型的MQ来存储循环Quee和执行任务的任务和逻辑。

In java, we have Executor which is designated for such tasks. 在java中,我们有Executor,它被指定用于这样的任务。 RxJava can easily create Scheduler from such Executor. RxJava可以从这样的Executor轻松创建Scheduler。

Below is example which shows how you can observe on main thread (not particular useful but show all required parts). 下面的示例显示了如何在主线程上观察(不是特别有用但显示所有必需的部分)。

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);
    }
}

And the last question, why your code does not terminate: 最后一个问题,为什么你的代码没有终止:

ThreadPoolExecutor uses non deamon threads by defult, thus your program does not end until they exist. ThreadPoolExecutor通过defult使用非deamon线程,因此您的程序在它们存在之前不会结束。 You should use shutdown method to close the threads. 您应该使用shutdown方法关闭线程。

Here's a simplified example updated for RxJava 2. It's the same concept as Marek's answer: an Executor that adds the runnables to a BlockingQueue that's being consumed on the caller's thread. 这是为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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM