Java 主线程中的SubscribeOn和observeOn

Java 主线程中的SubscribeOn和observeOn,java,rx-java,reactive-programming,rx-java2,Java,Rx Java,Reactive Programming,Rx Java2,我试图在执行器中使用subscribeOn和obsereOn,以便在异步任务完成后返回主线程。 我最终得到了这个代码,但它不起作用 @Test public void testBackToMainThread() throws InterruptedException { processValue(1); processValue(2); processValue(3); processValue(4); p

我试图在执行器中使用subscribeOn和obsereOn,以便在异步任务完成后返回主线程。 我最终得到了这个代码,但它不起作用

@Test
    public void testBackToMainThread() throws InterruptedException {
        processValue(1);
        processValue(2);
        processValue(3);
        processValue(4);
        processValue(5);
//        while (tasks.size() != 0) {
//            tasks.take().run();
//        }
        System.out.println("done");
    }

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


    private void processValue(int value) throws InterruptedException {
        Observable.just(value)
                .subscribeOn(Schedulers.io())
                .doOnNext(number -> processExecution())
                .observeOn(Schedulers.from(command -> tasks.add(command)))
                .subscribe(x -> System.out.println("Thread:" + Thread.currentThread().getName() + " value:" + x));
        tasks.take().run();
    }

    private void processExecution() {
        System.out.println("Execution in " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

关于

您的问题不会在RxJava2中出现。建议使用RxJava2。

我比较了RxJava-1.2.7和RxJava-2.0.7,找到了根本原因。现在我正在寻找解决办法


在RxJava-1.2.7.中,您可以看到
observeObserveon#145
,并在调用
请求时找到它
计划
任务。这意味着当您订阅时,它将调用
Executor.execute
。因此,您的任务队列立即接受
Runnable
。然后您获取并运行
Runnable
(这是实际的
ExecutorSchedulerWorker
),但是上游的
onNext
没有被调用(因为您睡眠时间为2000ms)。它将在
ObserveOnSubscriber#213
上返回
null
。当上游调用onNext(Integer)
时,任务将永远不会运行。

您的问题不会在RxJava2中出现。建议使用RxJava2。

我比较了RxJava-1.2.7和RxJava-2.0.7,找到了根本原因。现在我正在寻找解决办法


在RxJava-1.2.7.中,您可以看到
observeObserveon#145
,并在调用
请求时找到它
计划
任务。这意味着当您订阅时,它将调用
Executor.execute
。因此,您的任务队列立即接受
Runnable
。然后您获取并运行
Runnable
(这是实际的
ExecutorSchedulerWorker
),但是上游的
onNext
没有被调用(因为您睡眠时间为2000ms)。它将在
ObserveOnSubscriber#213
上返回
null
。当上游调用onNext(Integer)
时,该任务将永远不会运行。

这种方法的问题是,您不知道在给定的时间应该执行多少任务,也不知道在取消阻止主线程后应该等待的任务是否会死锁

我知道,1.x的任何扩展都不支持返回Java主线程。对于2.x,extensions项目中提供了以下功能:

public static void main(String[] args) {
    BlockingScheduler scheduler = new BlockingScheduler();

    scheduler.execute(() -> {
        Flowable.range(1,10)
        .subscribeOn(Schedulers.io())
        .observeOn(scheduler)
        .doAfterTerminate(() -> scheduler.shutdown())
        .subscribe(v -> System.out.println(v + " on " + Thread.currentThread()));
    });

    System.out.println("BlockingScheduler finished");
}

请注意调用
scheduler.shutdown()
,最终必须调用它才能释放主线程,否则,您的程序可能永远不会终止。

您的方法的问题是,您不知道在给定时间应该执行多少任务,也不知道在取消阻止主线程后应该等待的任务是否死锁

我知道,1.x的任何扩展都不支持返回Java主线程。对于2.x,extensions项目中提供了以下功能:

public static void main(String[] args) {
    BlockingScheduler scheduler = new BlockingScheduler();

    scheduler.execute(() -> {
        Flowable.range(1,10)
        .subscribeOn(Schedulers.io())
        .observeOn(scheduler)
        .doAfterTerminate(() -> scheduler.shutdown())
        .subscribe(v -> System.out.println(v + " on " + Thread.currentThread()));
    });

    System.out.println("BlockingScheduler finished");
}

请注意调用调度程序.shutdown(),最终必须调用该调用才能释放主线程,否则程序可能永远不会终止。

我只是根据akanord的建议更新代码,但这一做法似乎会阻止一个任务到另一个任务,并最终按顺序运行

使用代码:

   @Test
    public void testBackToMainThread() throws InterruptedException {
        processValue(1);
        processValue(2);
        processValue(3);
        processValue(4);
        processValue(5);
        System.out.println("done");
    }

    private void processValue(int value) throws InterruptedException {
        BlockingScheduler scheduler = new BlockingScheduler();
        scheduler.execute(() -> Flowable.just(value)
                .subscribeOn(Schedulers.io())
                .doOnNext(number -> processExecution())
                .observeOn(scheduler)
                .doAfterTerminate(() -> scheduler.shutdown())
                .subscribe(v -> System.out.println(v + " on " + Thread.currentThread())));
    }

    private void processExecution() {
        System.out.println("Execution in " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
以及输出

Execution in RxCachedThreadScheduler-1
1 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
2 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
3 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
4 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
5 on Thread[main,5,main]
done
我想要实现的是这个输出

Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
1 on Thread[main,5,main]
2 on Thread[main,5,main]
3 on Thread[main,5,main]
4 on Thread[main,5,main]
5 on Thread[main,5,main]
done

因此,每次主线程运行管道时,在另一个线程中运行onNext,然后它从方法返回,直到另一个线程完成并使其成为主线程返回管道。

我只是根据akanord的建议更新代码,但这一做法似乎会阻止一个任务到另一个任务,然后按顺序运行

使用代码:

   @Test
    public void testBackToMainThread() throws InterruptedException {
        processValue(1);
        processValue(2);
        processValue(3);
        processValue(4);
        processValue(5);
        System.out.println("done");
    }

    private void processValue(int value) throws InterruptedException {
        BlockingScheduler scheduler = new BlockingScheduler();
        scheduler.execute(() -> Flowable.just(value)
                .subscribeOn(Schedulers.io())
                .doOnNext(number -> processExecution())
                .observeOn(scheduler)
                .doAfterTerminate(() -> scheduler.shutdown())
                .subscribe(v -> System.out.println(v + " on " + Thread.currentThread())));
    }

    private void processExecution() {
        System.out.println("Execution in " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
以及输出

Execution in RxCachedThreadScheduler-1
1 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
2 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
3 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
4 on Thread[main,5,main]
Execution in RxCachedThreadScheduler-1
5 on Thread[main,5,main]
done
我想要实现的是这个输出

Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
Execution in RxCachedThreadScheduler-1
1 on Thread[main,5,main]
2 on Thread[main,5,main]
3 on Thread[main,5,main]
4 on Thread[main,5,main]
5 on Thread[main,5,main]
done


因此,每次主线程运行管道时,在另一个线程中运行onNext,然后它从方法返回,直到另一个线程完成并使其成为主线程返回管道。

我运行您的代码,并按预期输出。你的问题是什么?打印线程:永远不会发生只有执行:然后doneSorry,我不明白你的意思。你看到这个控制台打印吗??println(“线程:“+Thread.currentThread().getName()+”值:“+x”)它将打印
main
,因为您总是在主线程中执行并运行任务。我按预期运行您的代码并输出。你的问题是什么?打印线程:永远不会发生只有执行:然后doneSorry,我不明白你的意思。你看到这个控制台打印吗??println(“线程:+Thread.currentThread().getName()+”值:“+x”)它将打印
main
,因为您总是在主线程中执行任务。我认为标题的格式不正确。对不起,我还是不明白你的意思。你能详细说明一个例子吗?谢谢@保罗,我可以给你一个快速的解决方案。重复
任务。take().run()
两次,然后您将看到所需的输出。我认为标题格式不正确。对不起,我还是不明白你的意思。你能详细说明一个例子吗?谢谢@保罗,我可以给你一个快速的解决方案。重复
tasks.take().run()
两次,然后您将看到所需的输出。我尝试了您的aproach,但它似乎是按顺序运行的。你能看一下我的第二篇文章吗?我试过你的方法,但它似乎是按顺序运行的。你能看一下我的第二篇文章吗?你必须用blocking scheduler包含所有任务,而不是为每个项目单独创建一个blocking scheduler。如果我将BlockingScheduler定义为全局范围,那么它只执行第一个任务。在线程[main,5,main]上的RxCachedThreadScheduler-11中执行完毕我开始认为我想要的东西根本没有任何意义。无论如何,主线程都必须等待将来的某个时刻。您必须使用blocking scheduler包含所有任务,而不是为每个项目单独创建blocking scheduler。如果我将BlockingScheduler定义为全局作用域,则仅执行它的第一个任务。在线程[main]上的RxCachedThreadScheduler-1中执行