RxJava作为目前一款超火的框架,它便捷的线程切换一直被人们津津乐道,本文从源码的角度,来对RxJava的线程模型做一次深入理解。(注:本文的多处代码都并非原本的RxJava的源码,而是用来说明逻辑的伪代码)

入手体验

RxJava 中切换线程非常简单,例如最常见的异步线程处理,主线程回调的模型,可以很优雅的用如下代码来做处理:

  1. Observable.just("magic")
  2. .map(str -> doExpensiveWork(str))
  3. .subscribeOn(Schedulers.io())
  4. .observeOn(AndroidSchedulers.mainThread())
  5. .subscribe(obj -> System.out.print(String.valueOf(obj)));

如上,subscribeOn(Schedulers.io())保证了doExpensiveWork 函数发生在io线程,observeOn(AndroidSchedulers.mainThread())保证了subscribe 回调发生在Android 的主线程。所以,这自然而然的引出了本文的关键点,subscribeOnobserveOn到底区别在哪里?

流程浅析

要想回答上面的问题,我们首先需要对RxJava的流程有大体了解,一个Observable从产生,到最终执行subscribe,中间可以经历n个变换,每次变换会产生一个新的Observable,就像奥运开幕的传递火炬一样,每次火炬都会传递到下一个人,最终点燃圣火的是最后一个火炬手,即最终执行subscribe操作的是最后一个Observable,所以,每个Observable之间必须有联系,这种关系在代码中的体现就是,每个变换后的Observable都会持有上一个Observable 中OnSubscribe对象的引用(Observable.create 函数所需的参数),最终 Observable的subscribe函数中的关键代码是这一句:

  1. observable.onSubscribe.call(subscriber)

这个observable就是最后一个变换后的observable,那这个onSubscribe对象是谁呢?如何一个observable没有经过任何变换,直接执行了subscribe,当然就是我们在create中传入的onSubscribe, 但如果中间经过map、reduce等变换,这个onSubscribe显然就应该是创建变换后的observable传入的参数,大部分变换最终都交由lift函数:

  1. public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
  2. return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator));
  3. }

所以,上文所提到的onSubscribe对象应该是OnSubscribeLift的实例,而这个OnSubscribeLift所接收的两个参数,一个是前文提到的,上一个Observable中的OnSubscribe对象,而operator则是每种变换的一个抽象接口。再来看这个OnSubscribeLift对象的call方法:

  1. public void call(Subscriber<? super R> o) {
  2. Subscriber<? super T> st = operator.call(o);
  3. parent.call(st);

operator与parent就是前文提到的两个参数,可见,operator接口会拥有call方法,接收一个Subscriber, 并返回一个新的Subscriber对象,而接下来的parent.call(st)是回调上一层observable的onSubscribe的call方法,这样如此继续,一直到一个onSubscribe截止。这样我们首先理清了一条线路,就是从最后一个observable的subscribe后,OnSubscribe调用的顺序是从后向前的。

这就带来了另外一个疑问,从上面的代码可以看到,在执行parent.call(st)之前已经执行了operator.call(o)方法,如果call方法里就把变换的操作执行了的话,那似乎变换也会是从后向前传递的呀?所以这个operator.call方法绝对不是我们想象的那么简单。这里以map操作符为例,看源码:

  1. public Subscriber<? super T> call(final Subscriber<? super R> s) {
  2. MapSubscriber<T, R> parent = new MapSubscriber<T, R>(o, transformer);
  3. o.add(parent);
  4. return parent;
  5. }

这里果然没有执行变换操作,而是生成一个MapSubscriber对象,这里需要注意MapSubscriber构造函数的两个参数,transformer是真正要执行变换的Func1对象,这很好理解,那对于o这个Subscriber是哪一个呢?什么意思?举个

理解RxJava线程模型的更多相关文章

  1. 深入理解JVM线程模型

    1. jvm内存模型在描述jvm线程模型之前,我们先深入的理解下,jvm内存模型.在jvm1.8之前,jvm的逻辑结构和物理结构是对应的.即Jvm在初始化的时候,会为堆(heap),栈(stack), ...

  2. quartz源码分析——执行引擎和线程模型

    title: quartz源码分析--执行引擎和线程模型 date: 2017-09-09 23:14:48 categories: quartz tags: [quartz, 源码分析] --- - ...

  3. 理解 RxJava 的线程模型

    来源:鸟窝, colobu.com/2016/07/25/understanding-rxjava-thread-model/ 如有好文章投稿,请点击 → 这里了解详情 ReactiveX是React ...

  4. 理解微信小程序的双线程模型

    有过微信小程序开发经验的朋友应该都知道"双线程模型"这个概念,本文简单梳理一下双线程模型的一些科普知识,学识浅薄,若有错误欢迎指正. 我以前就职于「小程序·云开发」团队,在对外的一 ...

  5. 《深入理解Java内存模型》读书总结

    概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...

  6. HBase的Write Ahead Log (WAL) —— 整体架构、线程模型

    解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回放机制.每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中. 如果出 ...

  7. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  8. 【Todo】【转载】深入理解Java内存模型

    提纲挈领地说一下Java内存模型: 什么是Java内存模型 Java内存模型定义了一种多线程访问Java内存的规范.Java内存模型要完整讲不是这里几句话能说清楚的,我简单总结一下Java内存模型的几 ...

  9. 深入理解Java内存模型(一)——基础(转)

    转自程晓明的"深入理解Java内存模型"的博客 http://www.infoq.com/cn/articles/java-memory-model-1 并发编程模型的分类 在并发 ...

随机推荐

  1. 【转】Unity中添加组件的几种方法

    http://blog.csdn.net/monzart7an/article/details/23199647 一.在编辑器上面添加一个组件.这个不用多说. 二.在脚本中利用AddComponent ...

  2. 史上最臭名昭著五大软件Bug

    在现今数字年代,计算机bug不但困扰着每个程序员,更会无可避免影响我们的生活,小到每个人的衣食住行,大到国家经济,世界局势.随着我们的生活方式渐渐的数字化.互联网化,数字世界的找虫和杀虫就变得越来越重 ...

  3. php常用方法总结

    /** * created by Tina * time 2015-1-6 10:31 * textarea中传入字符串的处理,返回数组,传入的字符串以换行分割; * 拆分,压缩空格,去除空值,去重复 ...

  4. mongodb的一些基本操作

    1.列出所有数据库 >show dbs   2.使用数据库 >use memo   3.列出当前数据库的collections >show collections   4.显示当前正 ...

  5. ubuntu 常用命令集合版(二)【大侠勿喷,菜鸟欢迎】(转)

    原文:http://page.renren.com/600759338/note/729595757 1.shutdown: 关闭系统,如果停留在TTY,请改用halt, poweroff等命令常用参 ...

  6. C#实现鸽巢排序

    /// <summary> /// 鸽巢排序 /// 创建一个长度大于等于待排序数组array元素中最大值的标记数组mark, /// 将数组array中元素值个数映射到mark数组中. ...

  7. iOS 杂记

    一,demo 1,视图跳转 MaryPopin:  https://github.com/Backelite/MaryPopin 2,Nimbus是一个开源的iOS框架,比起Three20,Nimbu ...

  8. 十、Java基础---------面向对象之抽象类与接口

    抽象类(abstract)     当编写一个类时,时常会为该类定义一些方法,这些方法的使用用以描述该类的行为方式,那么这些方法都有具体的方法体.但是在某些情况下,某个父类只是知道子类应该包含怎样的方 ...

  9. Azure web role, work role 以及其他role

    Azure web role, work role 以及其他role 如果没有创建过web role 和work role的话可以参考如下文章来创建一下web role 和work role. htt ...

  10. TI CC2541的红外控制

    整整一个礼拜, 整了...大约40个小时吧, 最少.. 下面是结果, 只能做一个delay延时.: unsigned char Time;unsigned char IrValue[6];#pragm ...