RxJava线程切换原理

RxJava在圈子里越来越火,相信很大的一个原因就是它的线程切换。它的线程切换可以用优雅来形容,链式调用,简单、方便。今天,就让我们来窥探一下RxJava的线程切换原理。本次拆轮子,还是按原样,通过小例子,研读RxJava源码等来理解整个过程、结构、原理,我们首要的是先对线程切换的原理有个全局的概览,细节再慢慢来深入。

1 前言

线程的切换都是通过subscribeOn或者observeOn来进行,生产者的执行线程只受subscribeOn控制,不受observeOn影响。subscribeOn指定的线程环境能一直维持到第一次observeOn出现之前。要讲线程切换原理之前,我们先来看一下下面的几个类定义:

  • Operator
 
 
  1. /**
  2. * Operator function for lifting into an Observable.
  3. */
  4. public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {
  5. // cover for generics insanity
  6. }

Operator是Observable中定义的接口,即用户的逻辑操作,RxJava框架会调用lift方法将Operator包装成为Observable。

  • ObserveOnSubseriber

ObserveOnSubseriber是被订阅者的类,处理用户数据逻辑,也即生产者,用来产生用户数据的。

  • OperatorObserveOn

OperatorObserveOn是订阅者的类,接收数据的,也即消费者,消费生产者发送过来的数据。

  • Worker

Worker是线程真正执行的地方,也就是单独新建的一个线程或线程池中的某个线程。

2 原理解析

我们先创建一个Observable:

 
 
  1. Observable.just(null)
  2. .subscribeOn(Schedulers.io())
  3. .observeOn(AndroidSchedulers.mainThread())
  4. .subscribe();

just方法又是调用的ScalarSynchronousObservable,然后new一个OnSubscribe作为构造函数的参数,暂且叫做1号OnSubscribe,这个下面会再提到,也是线程切换的区别所在:

 
 
  1. protected ScalarSynchronousObservable(final T t) {
  2. super(new OnSubscribe<T>() {
  3. @Override
  4. public void call(Subscriber<? super T> s) {
  5. s.onNext(t);
  6. s.onCompleted();
  7. }
  8. });
  9. this.t = t;
  10. }

线程切换的要点在lift()函数里面,都是基于同一个基础的变换方法: lift(Operator)

先来看一下它的源码:

 
 
  1. public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
  2. return new Observable<R>(new OnSubscribe<R>() {
  3. @Override
  4. public void call(Subscriber<? super R> o) {
  5. try {
  6. Subscriber<? super T> st = hook.onLift(operator).call(o);
  7. try {
  8. // new Subscriber created and being subscribed with so 'onStart' it
  9. st.onStart();
  10. onSubscribe.call(st);
  11. } catch (Throwable e) {
  12. // localized capture of errors rather than it skipping all operators
  13. // and ending up in the try/catch of the subscribe method which then
  14. // prevents onErrorResumeNext and other similar approaches to error handling
  15. if (e instanceof OnErrorNotImplementedException) {
  16. throw (OnErrorNotImplementedException) e;
  17. }
  18. st.onError(e);
  19. }
  20. } catch (Throwable e) {
  21. if (e instanceof OnErrorNotImplementedException) {
  22. throw (OnErrorNotImplementedException) e;
  23. }
  24. // if the lift function failed all we can do is pass the error to the final Subscriber
  25. // as we don't have the operator available to us
  26. o.onError(e);
  27. }
  28. }
  29. });
  30. }

我们可以看到,调用lift()方法后(即执行subscribeOn或observeOn),是返回一个新的Observable,而不是调用者的Observable,这里同样是重新创建了一个OnSubscribe,暂且叫做2号OnSubscribe,我们再回头看看,这个OnSubscribe与前面提到的just()方法里面调用到的OnSubscribe不是同一个对象

这里是线程切换的关键点。当调用链来到lift()方法后,使用的是lift()所返回的新的 Observable,也就是它所触发的onSubscribe.call(subscriber)也是用新的Observable中的新 OnSubscribe,即我们上面命名的2号OnSubscribe。

3 OperatorSubscribeOn

再来看lift()函数的源码,它的第二个try方法体里面有个onSubscribe,这个OnSubscribe就是我们前面定义的1号onSubscribe,它就是我们调用just()方法后创建的原始Observable。

那它是怎么做到切换线程的呢?如上面的例子,subscribeOn(Schedulers.io()),它通过下面的代码(举例)产生一个新的Subscriber:

 
 
  1. Subscriber<? super T> st = hook.onLift(operator).call(o);//将新的Subscriber对象o传递给OperatorSubscribeOn,它里面的call()方法去创建新的Worker线程
  2. //OperatorSubscribeOn的call(o)方法
  3. @Override
  4. public Subscriber<? super Observable<T>> call(final Subscriber<? super T> subscriber) {
  5. final Worker inner = scheduler.createWorker();//新建线程
  6. subscriber.add(inner);
  7. return new Subscriber<Observable<T>>(subscriber) {
  8. @Override
  9. public void onCompleted() {
  10. // ignore because this is a nested Observable and we expect only 1 Observable<T> emitted to onNext
  11. }
  12. @Override
  13. public void onError(Throwable e) {
  14. subscriber.onError(e);
  15. }
  16. @Override
  17. public void onNext(final Observable<T> o) {
  18. inner.schedule(new Action0() {
  19. @Override
  20. public void call() {
  21. final Thread t = Thread.currentThread();
  22. o.unsafeSubscribe(new Subscriber<T>(subscriber) {
  23. @Override
  24. public void onCompleted() {
  25. subscriber.onCompleted();
  26. }
  27. @Override
  28. public void onError(Throwable e) {
  29. subscriber.onError(e);
  30. }
  31. @Override
  32. public void onNext(T t) {
  33. subscriber.onNext(t);
  34. }
  35. @Override
  36. public void setProducer(final Producer producer) {
  37. subscriber.setProducer(new Producer() {
  38. @Override
  39. public void request(final long n) {
  40. if (Thread.currentThread() == t) {//如果是当前线程,则在当前线程执行
  41. // don't schedule if we're already on the thread (primarily for first setProducer call)
  42. // see unit test 'testSetProducerSynchronousRequest' for more context on this
  43. producer.request(n);
  44. } else {//不是当前线程,将在新创建的Worker线程inner中执行
  45. inner.schedule(new Action0() {
  46. @Override
  47. public void call() {
  48. producer.request(n);
  49. }
  50. });
  51. }
  52. }
  53. });
  54. }
  55. });
  56. }
  57. });
  58. }
  59. };
  60. }

然后,通过调用1号OnSubscribe的call()方法 onSubscribe.call(st) 将新创建的Subscriber与原始的Observable关联起来,即新的Subscriber去订阅原始的Observable。这样,生产者

通过上面的代码可以知道,Scheduler类其实并不负责异步线程处理,它只负责通过createWorker()类创建出一个Worker对象,真正负责任务的延时处理。

4 OperatorObserveOn

observeOn方法内部也是调用了lift()方法,然后创建一个operator,

 
 
  1. //OperatorObserveOn.java
  2. @Override
  3. public Subscriber<? super T> call(Subscriber<? super T> child) {
  4. if (scheduler instanceof ImmediateScheduler) {
  5. // avoid overhead, execute directly
  6. return child;
  7. } else if (scheduler instanceof TrampolineScheduler) {
  8. // avoid overhead, execute directly
  9. return child;
  10. } else {
  11. ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child);
  12. parent.init();
  13. return parent;
  14. }
  15. }
  16. public ObserveOnSubscriber(Scheduler scheduler, Subscriber<? super T> child) {
  17. this.child = child;
  18. this.recursiveScheduler = scheduler.createWorker();//创建新的worker线程
  19. if (UnsafeAccess.isUnsafeAvailable()) {
  20. queue = new SpscArrayQueue<Object>(RxRingBuffer.SIZE);
  21. } else {
  22. queue = new SynchronizedQueue<Object>(RxRingBuffer.SIZE);
  23. }
  24. this.scheduledUnsubscribe = new ScheduledUnsubscribe(recursiveScheduler);
  25. }
  26. protected void schedule() {
  27. if (COUNTER_UPDATER.getAndIncrement(this) == 0) {
  28. recursiveScheduler.schedule(action);//用相应的线程进行数据输出调度
  29. }
  30. }

结合扔物线大大的图如下:


未完待续......

RxJava系列文章

5 参考

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值