Rxjava 高频面试题详解线程切换的原理

Rxjava 高频面试题详解线程切换的原理

Rxjava 面试中最高频的就是线程切换这块,我们可以进行将问题进行拆解

  1. subscribeOn 是怎么样把上游的工作的节点切换到指定线程上面的去的?
  2. observerOn 是怎么样把下游的工作的节点切换到指定线程上面的去的?

1.subscribeOn执行之后会创建一个ObservableSubscribeOn内部包含了我们上的souce和指定的Scheduler
,Scheduler我们就可以理解为指定线程,一旦Observer进行订阅了之后就会调用我们的subscribeActual
关键代码来了
// 将上一层的sourcer任务切换到 SubscribeTask中执行
scheduler.scheduleDirect(new SubscribeTask(parent))
// SubscribeTask 就是一个runnable

final class SubscribeTask implements Runnable {
    private final SubscribeOnObserver<T> parent;

    SubscribeTask(SubscribeOnObserver<T> parent) {
        this.parent = parent;
    }

    @Override
    public void run() {
        // 执行任务的地方
        source.subscribe(parent);
    }
}

而执行这个runnable 是在哪里呢,我们就要来看我们的Schedulers.io()这个线程策略了

public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
   // 这个Worker 就是我们    IoScheduler. EventLoopWorker
  final Worker w = createWorker();
 
    final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

    DisposeTask task = new DisposeTask(decoratedRun, w);
    //
    w.schedule(task, delay, unit);

    return task;
}

最后就会执行到我们的 NewThreadWorker scheduleActual

public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
   ...........
   //
    try {
      // 开启我们的线程池执行runnable
        if (delayTime <= 0) {
            f = executor.submit((Callable<Object>)sr);
        } else {
            f = executor.schedule((Callable<Object>)sr, delayTime, unit);
        }
        sr.setFuture(f);
    } catch (RejectedExecutionException ex) {
        if (parent != null) {
            parent.remove(sr);
        }
        RxJavaPlugins.onError(ex);
    }
    return sr;
}

上面是纯源码分析不是很好理解,我来转换一下思维给大家写一份伪代码

Observable.just("Hello world")
          .subscribeOn(Schedulers.io())
           .subscribe(result -> {
               
           })

可以直接等价于

Schedulers.io().createWorker().schedule {
   // 执行在 io线程中
   Observable.just("Hello world").subscribe()
}

看完这个伪代码大家是不是一目了然,同理observerOn的分析是一样的

2.observerOn(AndroidSchedules.mainThread()) 会执行到ObservableObserveOn中去

@Override
protected void subscribeActual(Observer<? super T> observer) {
    if (scheduler instanceof TrampolineScheduler) {
        source.subscribe(observer);
    } else {
       //  这个Worker 就是我们  HandlerScheduler.HandlerWorker
        Scheduler.Worker w = scheduler.createWorker();
        source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
    }
}

ObserveOnObserver 对象执行schedule 方法的时候 最终就会执行到 HandlerWorker的Schedule中去了

@Override
@SuppressLint("NewApi") // Async will only be true when the API is available to call.
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
  // 将run 进行保证
   ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
    // 创建一个meesage对象 
Message message = Message.obtain(handler, scheduled);
   message.obj = this; // Used as token for batch disposal of this worker's runnables.
   if (async) {
       message.setAsynchronous(true);
   }
   // 发送message消息
   handler.sendMessageDelayed(message, unit.toMillis(delay));
   // Re-check disposed state for removing in case we were racing a call to dispose().
   // 如果中断了就移除该message   
  if (disposed) {
       handler.removeCallbacks(scheduled);
       return Disposables.disposed();
   }
   return scheduled;
}

我们再写一个伪代码

Observable.just("Hello world")
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s -> {

        });

我们可以等价于

Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        String s = (String) msg.obj;

    }
};
Message message = Message.obtain();
message.obj = "Hello world";
handler.sendMessage(message);
总结

1.如果当subscribeOn多次调用的时候 只有最上端的线程切换才是有效的,因为subscribeOn是改变上游 的线程, observerOn多次调用的时候 只有最下端的线程切换才有效,因为observerOn是改变下游线程调度的,就是最近原则最靠近那个卡片就生效
2.多次切换只有一次生效

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值