RxJava 容易忽视的细节: subscribeOn() 方法没有按照预期地运行

df32547f46793d4af29a72c2d47400aa.png

我们知道,subscribeOn() 方法通过接收一个 Scheduler 参数,来指定对数据的处理运行在特定的线程调度器 Scheduler 上。若多次执行 subscribeOn() 方法,则只有最初的一次起作用。

subscribeOn() 方法只有第一次调用才有效,需要满足以下条件:

  • 被观察者必须是 Cold Observable。

  • 被观察者多次调用 subscribeOn() 之后,并不意味着线程只会切换一次,而是线程多次切换之后,最终切换到第一次设置的线程。

所以, subscribeOn() 方法的调用并非一直有效。本文会通过列举一些事例,分析其失效的原因。

一. 创建 Observable 后内部使用了多线程发射数据

使用 RxJava 创建 Observable 后,假如内部使用了多线程发射数据,会带来什么影响呢?

RxJava 会通过 Scheduler、subscribeOn() 来管理线程,但只有在不手动更改线程的情况下,它才会这样做。

通常情况下,RxJava 发射的数据会在同一个线程上,但是稍作一些变化,发射的数据来自不同的线程会怎样呢?

public static void main(String[] args) {
    Observable.create(emitter -> {
        emitter.onNext(1);
        new Thread("main") {
            @Override
            public void run() {
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
                emitter.onComplete();
            }
        }.start();
    })
    .subscribeOn(Schedulers.io())
    .map(integer -> {
        log(integer + " - I want this happen on an io thread");
        return integer + "";
    })
    .subscribe(s -> log("Consume: "+s));
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public static void log(String msg) {
    System.out.println("Current Thread Name:"+Thread.currentThread().getName() + ", "+ msg);
}

执行结果:

Current Thread Name:RxCachedThreadScheduler-1, 1 - I want this happen on an io thread
Current Thread Name:RxCachedThreadScheduler-1, Consume: 1
Current Thread Name:main, 2 - I want this happen on an io thread
Current Thread Name:main, Consume: 2
Current Thread Name:main, 3 - I want this happen on an io thread
Current Thread Name:main, Consume: 3
Current Thread Name:main, 4 - I want this happen on an io thread
Current Thread Name:main, Consume: 4

上述执行结果表明,除了 emitter 发射的 1 是在 io 线程中执行的,其余的数字都是在 main 线程中运行的。

一旦 create 操作符中的 emitter 发射了数值,甚至在新的线程发射了值,RxJava  还是会很高兴地接受这些数值并将它们进一步传递给流。此时 RxJava 没有改变线程,是因为 subscribeOn() 方法已经完成了工作,订阅已经在其他线程上进行了。这时,没有理由 RxJava 会再次更改线程。所以,会看到上述的运行结果。

二. Hot Observable 对 subscribeOn() 调用造成的影响

2.1 特殊的创建操作符 just

just 是一个比较“特殊”的创建操作符,just 的作用是将单个数据转换为发射这个单个数据的 Observable。just 类似于 fromXXX,但是 fromXXX 会将数组或 Iterable 的数据取出然后逐个发射,而 just 只是简单地原样发射,将数组或 Iterable 当作单个数据。另外,just 创建的不是一个 Cold Observable。

下面以 just、fromCallable 为例:

public static void main(String[] args) {
        System.out.println("from Just");
        Observable justObservable = Observable.just(new Random().nextInt());
        justObservable.subscribe(System.out::println);
        justObservable.subscribe(System.out::println);

        System.out.println("\nfrom Callable");

        Observable callableObservable = Observable.fromCallable(() -> new Random().nextInt());
        callableObservable.subscribe(System.out::println);
        callableObservable.subscribe(System.out::println);
    }

执行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值