很多开发者喜欢使用Rxjava的原因之一应该就是 – 自由的控制线程,而且控制的方式超级简单,利用 subscribeOn() 结合 observeOn()便可切换你想要的线程,超帅的有木有!!

调度器

所谓调度器,其实实质就是线程,想要程序执行的地方。Rxjava提供了一下几种调度器:

// 在当前线程立即开始执行任务
Schedulers.immediate( )

// 用于IO密集型任务,如异步阻塞IO操作,这个调度器的线程池会根据需要增长
// 对于普通的计算任务,请使用Schedulers.computation()
// Schedulers.io( )默认是一个CachedThreadScheduler,很像一个有线程缓存的新线程调度器
Schedulers.io( )

// 用于计算任务,如事件循环或和回调处理,不要用于IO操作(IO操作请使用Schedulers.io())
// 默认线程数等于处理器的数量
Schedulers.computation( )

// 为每个任务创建一个新线程
Schedulers.newThread( )

// 当其它排队的任务完成后,在当前线程排队开始执行
Schedulers.trampoline( )

// 使用指定的Executor作为调度器
Schedulers.from(executor)

subscribeOn和observeOn区别

subscribeOn和observeOn都可以切换线程,区别有2点:

(1)subscribeOn指定数据源执行的线程(也就是一开始创建的Observable被观察者里面的OnSubscribe的call方法要在那个线程执行);observeOn指定下一个开始观察者OnNext方法执行的线程。

(2)subscribeOn无论调用多少次,以最后一次指定的线程为准;observeOn每次调用后,都会影响下一个观察者执行的线程。

关于更多Rxjava线程控制,请参考 给 Android 开发者的 RxJava 详解 的“线程控制:Scheduler (二)”一节。

原理

因为Rxjava控制线程的代码较多,所以我还是以 Rxjava - 简单实现 基础加上线程控制的代码,这样解析起来更容易理解Rxjava的线程调度原理。

在Producer生产者类添加2个方法:

// Producer类
// 相当于Rxjava的subscribeOn方法
public Producer<T> produceOn(Scheduler scheduler) {
   return new Producer<>(new ProduceOnDataFactory<>(dataFactory, scheduler));
}
// 相当于Rxjava的observeOn方法
public Producer<T> consumeOn(Scheduler scheduler) {
    return new Producer<>(new ConsumeOnDataFactory<>(this, scheduler));
}

我们还是以例子来分析:

Log.e(getClass().getName(), "origin thread name ---> " + Thread.currentThread().getName());
Producer.create(new DataFactory<String>() {
    @Override
    public void create(Consumer<String> consumer) {
        Log.e(getClass().getName(), "create thread name ---> " + Thread.currentThread().getName());
        consumer.onNext("Hello");
        consumer.onNext("World");
        consumer.onCompleted();
    }
}).produceOn(Schedulers.getWorkScheduler()).consumeOn(Schedulers.getMainScheduler()).add(new Consumer<String>() {
    @Override
    public void onCompleted() {
        Log.e(getClass().getName(), "completed is called");
    }
    @Override
    public void onNext(String result) {
        Log.e(getClass().getName(), "onNext thread name ---> " + Thread.currentThread().getName());
        Log.e(getClass().getName(), "course name : " + result);
    }
    @Override
    public void onError(Exception exception) {
        Log.e(getClass().getName(), "error is called");
    }
});

打印结果:

origin thread name ---> main
create thread name ---> pool-1-thread-1
onNext thread name ---> main
course name : Hello
onNext thread name ---> main
course name : World
completed is called

从结果看,线程发生了切换,我们来分析代码,初始的Producer调用了produceOn方法:

// Producer类
// 相当于Rxjava的subscribeOn方法
public Producer<T> produceOn(Scheduler scheduler) {
   return new Producer<>(new ProduceOnDataFactory<>(dataFactory, scheduler));
}

创建了ProduceOnDataFactory数据工厂,返回新的Producer生产者,新的Producer生产者又调用了consumeOn方法:

// Producer类
// 相当于Rxjava的observeOn方法
public Producer<T> consumeOn(Scheduler scheduler) {
    return new Producer<>(new ConsumeOnDataFactory<>(this, scheduler));
}

创建了ConsumeOnDataFactory数据工厂,返回新的Producer生产者,然后调用add消费者,此时ConsumeOnDataFactory的create方法先调用:

// ConsumeOnDataFactory类
// 此时的source是produceOn之后创建的Producer生产者
private Producer<T> source;
// 调度器,Schedulers.getMainScheduler()
private Scheduler scheduler;
@Override
// consumer为例子中最后add的消费者
public void create(Consumer<T> consumer) {
    // 代理consumer,待会再解析
    ScheduleConsumer scheduleConsumer = new ScheduleConsumer(consumer, scheduler);
    source.add(scheduleConsumer);
}

create方法中,最终调用了source的add方法,那么produceOn之后创建的Producer生产者的数据工厂ProduceOnDataFactory的create方法就会执行:

// ProduceOnDataFactory类
// source为初始创建的数据工厂,也就是例子中 Producer.create(这个工厂)
private DataFactory<T> source;
// 调度器,Schedulers.getWorkScheduler()
private Scheduler scheduler;
@Override
// consumer为ScheduleConsumer
public void create(final Consumer<T> consumer) {
    scheduler.schedule(new Runnable() {
        @Override
        public void run() {
            source.create(consumer);
        }
    });
}

这里可以说一下调度器,我简单实现了一下:

// 调度器接口
public interface Scheduler {
    void schedule(Runnable command);
}

// 主线程调度器
public class MainScheduler implements Scheduler {
    private static Handler handler;
    @Override
    public void schedule(Runnable command) {
        getWorker().post(command);
    }
    private static Handler getWorker() {
        synchronized (MainScheduler.class) {
            if (handler == null) {
                handler = new Handler(Looper.getMainLooper());
            }
            return handler;
        }
    }
}

// 工作(异步)线程调度器
public class WorkScheduler implements Scheduler {
    private static ExecutorService executorService;
    @Override
    public void schedule(Runnable command) {
        getWorker().execute(command);
    }
    private ExecutorService getWorker() {
        synchronized (WorkScheduler.class) {
            if (executorService == null) {
                executorService = Executors.newCachedThreadPool();
            }
            return executorService;
        }
    }
}

// 总调度器
public class  Schedulers {
    private static class MainSchedulerHolder {
        private static final MainScheduler INSTANCE = new MainScheduler();
    }
    private static class WorkSchedulerHolder {
        private static final WorkScheduler INSTANCE = new WorkScheduler();
    }
    public static Scheduler getMainScheduler() {
        return MainSchedulerHolder.INSTANCE;
    }
    public static Scheduler getWorkScheduler() {
        return WorkSchedulerHolder.INSTANCE;
    }
}

关于调度器很容易看得明白的,不再详解。我们继续回到ProduceOnDataFactory的create方法:

// ProduceOnDataFactory类
// source为初始创建的数据工厂,也就是例子中 Producer.create(这个工厂)
private DataFactory<T> source;
// 调度器Schedulers.getWorkScheduler(),工作线程调度器
private Scheduler scheduler;
@Override
// consumer为ScheduleConsumer
public void create(final Consumer<T> consumer) {
    scheduler.schedule(new Runnable() {
        @Override
        public void run() {
            source.create(consumer);
        }
    });
}

调用WorkScheduler的schedule方法,便把source的create扔进线程池执行了,这就达到切换线程的效果了。我们继续,当source的create方法执行consumer.onNext(“Hello”)时,ScheduleConsumer的onNext方法就会执行:

// ScheduleConsumer类
// consumer为例子中最后add的消费者
private Consumer<T> source;
// 调度器,Schedulers.getMainScheduler()
private Scheduler scheduler;
@Override
public void onNext(final T result) {
    // 调用主线程执行source的onNext方法
    scheduler.schedule(new Runnable() {
        @Override
        public void run() {
            source.onNext(result);
        }
    });
}

这样,例子中最后add的消费者的onNext方法放到主线程执行了。是不是很清晰?!
还不是很清晰,还是建议看 给 Android 开发者的 RxJava 详解 的“线程控制:Scheduler (二)”一节。

代码已经更新到我的github库,地址:https://github.com/JohanMan/simplerxjava,欢迎下载研究!!

参考资料

给 Android 开发者的 RxJava 详解
RxJava多线程操作