Rxjava线程调度模型

rxjava的线程控制(调度/切换):subscribeOn()/ observerOn()

1.rxjava线程调度控制的作用:

        rxjava通过线程调度可以控制Observable(被观察者)/观察者(Observer)工作的线程的类型

2.为什么要进行rxjava的线程的调度切换:

        在rxjava中被观察者(Observable) / 观察者(Observer)的工作线程 = 创建自身的线程

即在安卓中如果被观察者(Observable) / 观察者(Obesrver)在主线程被创建那么它们也工作(发送事件 / 接收响应事件) 在主线程中

通过以下的例子观察被观察者Observable / 观察者Observer的工作线程:

//观察Rxjava中被观察者Observable/观察者Observer的默认工作线程
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onNext(3);
                e.onComplete();
                Log.d(TAG, "Observable被观察者当前的工作线程为: " + Thread.currentThread().getName());
            }
        }).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "onSubscribe: 开始采用subscribe连接 thread = " + Thread.currentThread().getName());
            }

            @Override
            public void onNext(Integer integer) {
                Log.d(TAG, "onNext: " + integer + " thread = " + Thread.currentThread().getName());
            }

            @Override
            public void onError(Throwable e) {
                Log.d(TAG, "onError: " + e.getMessage() + " thread = " + Thread.currentThread().getName());
            }

            @Override
            public void onComplete() {
                Log.d(TAG, "onComplete: thread = " + Thread.currentThread().getName());
            }
        });

打印结果(Observable和observer都工作在创建它们的线程中):

以上这种操作在安卓中的问题:

由于在安卓中主线程是不能做耗时操作的(比如:联网操作,大文件的IO, 数据库查询等)否则会导致ANR异常的产生

因此在安卓中我们一般会采用开启新的线程配合Handler 或者采用AsyncTask的方式在子线程中进行耗时的操作然后采用

Handler发消息或者AsyncTask回调到主线程中进行更新UI的操作,因此rxjava的Observable被观察者和观察者

Observer工作在创建它们的线程中的这种方式在安卓中是有一定问题的,由此我们就需要引入rxjava的线程调度的控制符

也就是需要实现以下的这种操作:

    被观察者Observable在子线程中产生事件发送数据(实现耗时的操作)

    观察者Observer在安卓主线程中订阅并响应子线程中Observable发送的事件(如更新UI的操作)

若需要解决以上的问题需要用到rxjava的调度器Scheduler配合我们的subscribeOn()/ observeOn()操作来控制调度线程

功能性操作符observeOn()  /  subscribeOn()功能操作符

以上两个操作符的作用是控制观察者Observer /  被观察者Observable工作的线程类型

在rxjava和rxAndroid中Schedulers/ AndroidSchedulers内置了几种线程类型:

类型含义
Schedulers.io()
用于IO密集型的操作,例如读写SD卡文件,查询数据库,访问网络等,具有线程缓存机制,在此调度器接收到任务后,先检查线程缓存池中,是否有空闲的线程,如果有,则复用,如果没有则创建新的线程,并加入到线程池中,如果每次都没有空闲线程使用,可以无上限的创建新线程
Schedulers.newThread()

在每执行一个任务时创建一个新的线程,不具有线程缓存机制,因为创建一个新的线程比复用一个线程的成本更高,虽然使用Schedulers.io( )的地方,都可以使用Schedulers.newThread( ),但是,Schedulers.newThread( )的效率没有Schedulers.io( )高。

Schedulers.single()
拥有一个线程单例,所有的任务都在这一个线程中执行,当此线程中有任务执行时,其他任务将会按照先进先出的顺序依次执行。
Schedulers.trampoline()
在当前线程立即执行任务,如果当前线程有任务在执行,则会将其暂停,等插入进来的任务执行完之后,再将未完成的任务接着执行。
Schedulers.computation()
用于CPU 密集型计算任务,即不会被 I/O 等操作限制性能的耗时操作,例如xml,json文件的解析,Bitmap图片的压缩取样等,具有固定的线程池,大小为CPU的核数。不可以用于I/O操作,因为I/O操作的等待时间会浪费CPU。
AndroidSchedulers.mainThread()
在Android UI线程中执行任务,为Android开发定制。
Schedulers.from(Executors executor)
指定一个线程调度器,由此调度器来控制任务的执行策略.

注:

    1. 以上的线程rxjava都是用线程池来进行维护的因此线程调度的效率都比较高

    2.在RxJava2中,废弃了RxJava1中的Schedulers.immediate( )      

       在RxJava1中,Schedulers.immediate( )的作用为在当前线程立即执行任务,功能等同于RxJava2中的Schedulers.trampoline( )

       而Schedulers.trampoline( )在RxJava1中的作用是当其它排队的任务完成后,在当前线程排队开始执行接到的任务,

      有点像RxJava2中的Schedulers.single(),但也不完全相同,因为Schedulers.single()不是在当前线程而是在一个线程

     单例中排队执行任务.

具体使用:

Observable.subscribeOn(Schedulers.Thread):指定被观察者Observable 发送事件的线程(传入RxJava内置的线程类型) 

 Observable.observeOn(Schedulers.Thread):指定观察者Observer 接收 & 响应事件的线程(传入RxJava内置的线程类型)

通过订阅(subscribe)连接观察者和被观察者

Observable.subscribeOn(Schedulers.newThread()) // 1. 指定被观察者Observable 生产事件的线程

.observeOn(AndroidSchedulers.mainThread()) // 2. 指定观察者Observer 接收 & 响应事件的线程

.subscribe(observer); // 3. 最后再通过订阅(subscribe)连接观察者Observer和被观察者Observable

1.使用一次subscribeOn() 和使用一次observeOn()  进行线程调度

//使用一次subscribeOn() 和 observeOn()的线程调度
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.e(TAG, "上游被观察者Observable在" + Thread.currentThread().getName() + "线程, 生产一个事件: " + i );
                    SystemClock.sleep(1000);
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.d(TAG, "下游观察者Observer在" + Thread.currentThread().getName() + "线程接收响应到了事件: " + integer);
                    }
                });

打印结果:

2.使用两次subscribeOn()和一次observeOn()进行线程调度

//使用两次subscribeOn() 和 一次observeOn()的线程调度
        //通过两次设置subscribeOn()发射和处理数据在不同的线程,但是最终起作用的是第一次设置的工作线程
        //由此可以得出多次设置subscribeOn()设置被观察者Observable工作的线程最终起作用的是第一次设置的线程
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.e(TAG, "上游被观察者Observable在" + Thread.currentThread().getName() + "线程, 生产一个事件: " + i );
                    SystemClock.sleep(1000);
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.w(TAG, "map操作符在" + Thread.currentThread().getName() + "线程处理了事件: " + integer);
                        return integer * 2;
                    }
                })
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.d(TAG, "下游观察者Observer在" + Thread.currentThread().getName() + "线程接收响应到了事件: " + integer);
                    }
                });

打印结果:

3.使用一次subscribeOn() 和两次observeOn()

//使用一次subscribeOn() 和两次 observeOn()进行线程调度
        //可以看到每次通过observeOn()设置观察者Observer的响应接收上游Observable发射的事件的线程都是起作用的
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.e(TAG, "上游被观察者Observable在" + Thread.currentThread().getName() + "线程, 生产一个事件: " + i );
                    SystemClock.sleep(1000);
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).subscribeOn(Schedulers.computation())  //指定Observable被观察者在computation线程上生产并发射事件
                .observeOn(Schedulers.io())  //指定观察者Observer在io线程上进行map变换操作
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.w(TAG, "map操作符在" + Thread.currentThread().getName() + "线程处理了事件: " + integer);
                        return integer * 2;
                    }
                }).observeOn(AndroidSchedulers.mainThread())  //在指定观察者Observer在main主线程进行数据的最终接收
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.d(TAG, "下游观察者Observer在" + Thread.currentThread().getName() + "线程接收响应到了事件: " + integer);
                    }
                });

打印结果:

通过以上的三个示例可以总结出subscribeOn()和observeOn()操作符的使用特点:

subscribeOn()来指定上游(Observable)对数据的处理运行在特定的线程调度器Scheduler上,直到遇到observeOn()

                      改变线程调度器若多次设定,则只有第一次起作用。

observeOn()指定下游(Observer)操作运行在特定的线程调度器Scheduler上。若多次设定,每次均起作用。

 

4.Schedulers.trampoline() 线程

我们可以发现虽然Observer在接收到数据后,延迟了两秒才处理,但是Observable依然在Observer将数据处理

完之后才开始发射下一条。

Schedulers.trampoline()的作用在当前线程立即执行任务,如果当前线程有任务在执行,则会将其暂停,等插入进

来的任务执行完之后,再将未完成的任务接着执行。

//使用trampoline进行线程的调度实现上游发射一个数据 下游就对应的接收一个数据
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.e(TAG, "上游被观察者Observable在" + Thread.currentThread().getName() + "线程, 生产一个事件: " + i );
                    SystemClock.sleep(500);
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(Schedulers.trampoline())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        SystemClock.sleep(1000);
                        Log.d(TAG, "下游观察者Observer在" + Thread.currentThread().getName() + "线程接收响应到了事件: " + integer);
                    }
                });

打印结果:

5.Schedulers.single()线程操作符

//使用single()进行线程的调度
        //如果使用single()线程那么执行的顺序是一一来执行的
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < 4; i++) {
                    Log.e(TAG, "上游被观察者Observable在" + Thread.currentThread().getName() + "线程, 生产一个事件: " + i );
                    SystemClock.sleep(500);
                    e.onNext(i);
                }
                e.onComplete();
            }
        }).subscribeOn(Schedulers.single())
                .observeOn(Schedulers.single())
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(@NonNull Integer integer) throws Exception {
                        Log.w(TAG, "map操作符在" + Thread.currentThread().getName() + "线程处理了事件: " + integer);
                        return integer * 2;
                    }
                })
                .observeOn(Schedulers.single())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(@NonNull Integer integer) throws Exception {
                        Log.d(TAG, "下游观察者Observer在" + Thread.currentThread().getName() + "线程接收响应到了事件: " + integer);
                    }
                });

打印结果:

如果不需要线程的执行结果我们可以直接使用Schedulers来开启线程执行异步耗时的操作
public void schedulers_demo(View view){

        mWorker = Schedulers.io().createWorker().schedule(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(4000);
                Log.d(TAG, "Schedulers调度器的使用: " + Thread.currentThread().getName());
            }
        });
    }

关于subscribeOn()和observeOn()的一些使用建议看一下示例:

Observable.create(new ObservableOnSubscribe<Integer>() {
                @Override
                public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
                    //工作在计算线程
                    Log.d(TAG, "subscribe: thread = " + Thread.currentThread().getName());
                    e.onNext(1);
                    e.onNext(2);
                    e.onComplete();
                }
            }).observeOn(Schedulers.io())
                    .flatMap(new Function<Integer, ObservableSource<Integer>>() {

                        @Override
                        public ObservableSource<Integer> apply(@NonNull final Integer integer) throws Exception {
                            //工作在io线程
                            Log.d(TAG, "apply : thread = " + Thread.currentThread().getName());

                          return Observable.create(new ObservableOnSubscribe<Integer>() {
                              @Override
                              public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
                                  //工作在主线程
                                  Log.d(TAG, "subscribe flatmap+: thread = " + Thread.currentThread().getName());
                                  e.onNext(integer * 2);
                              }
                          }).subscribeOn(AndroidSchedulers.mainThread());
                        }
                    })
                    .map(new Function<Integer, Integer>() {
                        @Override
                        public Integer apply(@NonNull Integer integer) throws Exception {
                            //工作在主线程
                            Log.d(TAG, "apply map : thread = " + Thread.currentThread().getName());
                            return integer * 10;
                        }
                    }).subscribeOn(Schedulers.computation())
                    .subscribe(new Consumer<Integer>() {
                        @Override
                        public void accept(@NonNull Integer integer) throws Exception {
                            //工作在主线程
                            Log.d(TAG, "accept: 接收 " + integer + " thread = " + Thread.currentThread().getName());
                        }
                    });

注:

 示意图中,不同的颜色代表着代码执行时候工作在不同的线程中

黄色: Schedulers.computation() 计算线程

粉色:Schedulers.io() io线程

红褐色:Android 主线程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值