揭秘 RxJava 线程调度模块:从源码到原理的深度剖析
一、引言
在当今的软件开发领域,异步编程和多线程处理变得越来越重要。RxJava 作为一个强大的响应式编程库,为我们提供了简洁而高效的异步编程解决方案。其中,线程调度模块是 RxJava 的核心功能之一,它允许开发者轻松地控制任务在不同线程上的执行,从而提高程序的性能和响应能力。
本博客将深入分析 RxJava 线程调度模块的使用原理,从源码级别详细剖析其实现细节。我们将从基本概念入手,逐步深入到调度器的创建、任务调度、线程切换等核心部分,帮助读者全面理解 RxJava 线程调度的工作机制。
二、RxJava 线程调度基础概念
2.1 调度器(Scheduler)的概念
在 RxJava 中,调度器(Scheduler)是用于控制任务执行线程的核心组件。调度器负责管理线程池,并将任务分配到合适的线程上执行。不同类型的调度器适用于不同的场景,例如 CPU 密集型任务、I/O 密集型任务等。
RxJava 提供了几种内置的调度器,以下是一些常用的调度器及其用途:
Schedulers.io()
:适用于 I/O 密集型任务,如网络请求、文件读写等。它维护一个线程池,线程数量会根据需求动态调整。
import io.reactivex.schedulers.Schedulers;
// 获取 I/O 调度器
Scheduler ioScheduler = Schedulers.io();
Schedulers.computation()
:用于 CPU 密集型任务,如数据处理、计算等。线程池大小通常与 CPU 核心数相同。
import io.reactivex.schedulers.Schedulers;
// 获取计算调度器
Scheduler computationScheduler = Schedulers.computation();
Schedulers.single()
:使用一个单线程来执行任务,任务会按顺序依次执行。
import io.reactivex.schedulers.Schedulers;
// 获取单线程调度器
Scheduler singleScheduler = Schedulers.single();
Schedulers.trampoline()
:在当前线程立即执行任务,如果当前线程正在执行其他任务,则将新任务放入队列,等待当前任务执行完毕后再执行。
import io.reactivex.schedulers.Schedulers;
// 获取 trampoline 调度器
Scheduler trampolineScheduler = Schedulers.trampoline();
Schedulers.newThread()
:为每个任务创建一个新的线程来执行。
import io.reactivex.schedulers.Schedulers;
// 获取新线程调度器
Scheduler newThreadScheduler = Schedulers.newThread();
2.2 subscribeOn() 和 observeOn() 方法
subscribeOn()
和 observeOn()
是 RxJava 中用于控制线程调度的两个重要方法。
2.2.1 subscribeOn() 方法
subscribeOn()
方法用于指定 Observable
发射数据的线程。无论该方法在链式调用中出现多少次,只有第一次调用会生效。
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
// 创建一个 Observable
Observable<Integer> observable = Observable.just(1, 2, 3);
// 指定 Observable 发射数据的线程为 I/O 线程
observable.subscribeOn(Schedulers.io())
.subscribe(System.out::println);
在上述代码中,subscribeOn(Schedulers.io())
表示 Observable
发射数据的操作将在 I/O 线程上执行。
2.2.2 observeOn() 方法
observeOn()
方法用于指定 Observer
接收数据的线程。该方法可以在链式调用中多次使用,每次调用都会改变后续操作所在的线程。
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
// 创建一个 Observable
Observable<Integer> observable = Observable.just(1, 2, 3);
// 指定 Observable 发射数据的线程为 I/O 线程
// 指定 Observer 接收数据的线程为计算线程
observable.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe(System.out::println);
在上述代码中,observeOn(Schedulers.computation())
表示 Observer
接收数据的操作将在计算线程上执行。
三、调度器的创建与管理
3.1 Schedulers 类
Schedulers
类是 RxJava 中调度器的工厂类,它提供了多个静态方法用于获取不同类型的调度器。以下是 Schedulers
类的部分源码:
public final class Schedulers {
// 单例模式,确保每个调度器只有一个实例
private static final Scheduler IO;
private static final Scheduler COMPUTATION;
private static final Scheduler SINGLE;
private static final Scheduler TRAMPOLINE;
private static final Scheduler NEW_THREAD;
static {
// 初始化调度器实例
IO = RxJavaPlugins.initIoScheduler(new IOTask());
COMPUTATION = RxJavaPlugins.initComputationScheduler(new ComputationTask());
SINGLE = RxJavaPlugins.initSingleScheduler(new SingleTask());
TRAMPOLINE = RxJavaPlugins.initTrampolineScheduler(new TrampolineTask());
NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(new NewThreadTask());
}
// 获取 I/O 调度器
public static Scheduler io() {
return RxJavaPlugins.onIoScheduler(IO);
}
// 获取计算调度器
public static Scheduler computation() {
return RxJavaPlugins.onComputationScheduler(COMPUTATION);
}
// 获取单线程调度器
public static Scheduler single() {
return RxJavaPlugins.onSingleScheduler(SINGLE);
}
// 获取 trampoline 调度器
public static Scheduler trampoline() {
return RxJavaPlugins.onTrampolineScheduler(TRAMPOLINE);
}
// 获取新线程调度器
public static Scheduler newThread() {
return RxJavaPlugins.onNewThreadScheduler(NEW_THREAD);
}
}
从源码中可以看出,Schedulers
类使用静态代码块初始化了各个调度器的实例,并通过静态方法提供给外部使用。RxJavaPlugins
用于对调度器进行全局的初始化和配置。
3.2 调度器的创建过程
以 Schedulers.io()
为例,分析调度器的创建过程。
public static Scheduler io() {
return RxJavaPlugins.onIoScheduler(IO);
}
RxJavaPlugins.onIoScheduler(IO)
方法会对调度器进行一些全局的配置和处理,最终返回 IO
调度器实例。
在静态代码块中,IO
调度器的初始化代码如下:
IO = RxJavaPlugins.initIoScheduler(new IOTask());
RxJavaPlugins.initIoScheduler()
方法会调用 IOTask
来创建 IO
调度器。IOTask
是一个内部类,它实现了 SchedulerSupplier
接口,用于创建具体的调度器实例。
static final class IOTask implements SchedulerSupplier {
@Override
public Scheduler get() {
return new IoScheduler();
}
}
IoScheduler
是 IO
调度器的具体实现类,它继承自 Scheduler
类。
public final class IoScheduler extends Scheduler {
// 线程池管理器
private final CachedWorkerPool pool;
// 线程名称前缀
private static final String WORKER_NAME_PREFIX = "RxCachedThreadScheduler";
// 线程工厂
private static final ThreadFactory THREAD_FACTORY = new RxThreadFactory(WORKER_NAME_PREFIX);
public IoScheduler() {
// 初始化线程池管理器
this.pool = new CachedWorkerPool(60, TimeUnit.SECONDS, THREAD_FACTORY);
}
@Override
public Worker createWorker() {
// 创建一个工作线程
return new EventLoopWorker(pool.get());
}
}
在 IoScheduler
的构造函数中,会创建一个 CachedWorkerPool
实例,用于管理线程池。createWorker()
方法用于创建一个工作线程,该工作线程负责执行具体的任务。
四、任务调度原理
4.1 任务调度的基本流程
在 RxJava 中,任务调度的基本流程如下:
- 创建任务:通过
Observable
或Flowable
等创建一个可观察对象,并定义相应的任务逻辑。 - 指定调度器:使用
subscribeOn()
和observeOn()
方法指定任务执行的线程。 - 订阅任务:调用
subscribe()
方法订阅可观察对象,触发任务的执行。 - 调度器分配任务:调度器根据任务的类型和指定的线程,将任务分配到合适的线程上执行。
4.2 任务调度的源码分析
以 subscribeOn()
方法为例,分析任务调度的源码。
public final Observable<T> subscribeOn(Scheduler scheduler) {
// 检查调度器是否为空
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
// 创建一个 ObservableSubscribeOn 对象,将当前 Observable 和调度器作为参数传入
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
subscribeOn()
方法会创建一个 ObservableSubscribeOn
对象,该对象继承自 AbstractObservableWithUpstream
,用于包装原始的 Observable
并指定调度器。
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
@Override
public void subscribeActual(final Observer<? super T> s) {
// 创建一个 SubscribeOnObserver 对象,用于处理订阅逻辑
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
s.onSubscribe(parent);
// 使用调度器的 scheduleDirect() 方法安排任务在指定线程执行
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
static final class SubscribeOnObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable {
private static final long serialVersionUID = 8094547886072529208L;
final Observer<? super T> actual;
SubscribeOnObserver(Observer<? super T> actual) {
this.actual = actual;
}
@Override
public void onSubscribe(Disposable s) {
DisposableHelper.setOnce(this, s);
}
@Override
public void onNext(T t) {
actual.onNext(t);
}
@Override
public void onError(Throwable t) {
actual.onError(t);
}
@Override
public void onComplete() {
actual.onComplete();
}
@Override
public void dispose() {
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
void setDisposable(Disposable d) {
DisposableHelper.setOnce(this, d);
}
}
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
// 调用原始 Observable 的 subscribe() 方法,触发任务执行
source.subscribe(parent);
}
}
}
在 subscribeActual()
方法中,会创建一个 SubscribeOnObserver
对象,并调用调度器的 scheduleDirect()
方法安排 SubscribeTask
任务在指定线程执行。SubscribeTask
的 run()
方法会调用原始 Observable
的 subscribe()
方法,从而触发任务的执行。
4.3 线程切换的实现
observeOn()
方法用于实现线程切换,以下是 observeOn()
方法的源码分析。
public final Observable<T> observeOn(Scheduler scheduler) {
// 检查调度器是否为空
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
// 创建一个 ObservableObserveOn 对象,将当前 Observable 和调度器作为参数传入
return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler));
}
observeOn()
方法会创建一个 ObservableObserveOn
对象,该对象同样继承自 AbstractObservableWithUpstream
。
public final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
final boolean delayError;
final int bufferSize;
public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {
super(source);
this.scheduler = scheduler;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
// 如果调度器是 TrampolineScheduler,则直接订阅原始 Observable
source.subscribe(observer);
} else {
// 创建一个 ObserveOnObserver 对象,用于处理线程切换逻辑
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
private static final long serialVersionUID = 6576896619930983584L;
final Observer<? super T> actual;
final Scheduler.Worker worker;
final boolean delayError;
final int bufferSize;
Disposable s;
SimpleQueue<T> queue;
volatile boolean done;
Throwable error;
volatile boolean disposed;
int sourceMode;
ObserveOnObserver(Observer<? super T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {
this.actual = actual;
this.worker = worker;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
public void onSubscribe(Disposable s) {
if (DisposableHelper.validate(this.s, s)) {
this.s = s;
if (s instanceof QueueDisposable) {
@SuppressWarnings("unchecked")
QueueDisposable<T> qd = (QueueDisposable<T>) s;
int m = qd.requestFusion(QueueDisposable.ANY | QueueDisposable.BOUNDARY);
if (m == QueueDisposable.SYNC) {
sourceMode = m;
queue = qd;
done = true;
actual.onSubscribe(this);
schedule();
return;
}
if (m == QueueDisposable.ASYNC) {
sourceMode = m;
queue = qd;
actual.onSubscribe(this);
return;
}
}
queue = new SpscLinkedArrayQueue<T>(bufferSize);
actual.onSubscribe(this);
}
}
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
@Override
public void onError(Throwable t) {
if (done) {
RxJavaPlugins.onError(t);
return;
}
error = t;
done = true;
schedule();
}
@Override
public void onComplete() {
if (done) {
return;
}
done = true;
schedule();
}
@Override
public void run() {
if (disposed) {
return;
}
boolean canComplete = delayError || sourceMode != QueueDisposable.ASYNC;
SimpleQueue<T> q = queue;
Observer<? super T> a = actual;
int missed = 1;
for (; ; ) {
if (checkTerminated(done, q.isEmpty(), a, canComplete)) {
return;
}
for (; ; ) {
boolean d = done;
T v;
try {
v = q.poll();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
worker.dispose();
return;
}
boolean empty = v == null;
if (checkTerminated(d, empty, a, canComplete)) {
return;
}
if (empty) {
break;
}
a.onNext(v);
}
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
boolean checkTerminated(boolean d, boolean empty, Observer<? super T> a, boolean canComplete) {
if (disposed) {
queue.clear();
return true;
}
if (d) {
Throwable e = error;
if (delayError) {
if (empty) {
if (e != null) {
a.onError(e);
} else {
a.onComplete();
}
worker.dispose();
return true;
}
} else {
if (e != null) {
queue.clear();
a.onError(e);
worker.dispose();
return true;
} else if (empty) {
a.onComplete();
worker.dispose();
return true;
}
}
}
return false;
}
@Override
public void dispose() {
if (!disposed) {
disposed = true;
s.dispose();
worker.dispose();
}
}
@Override
public boolean isDisposed() {
return disposed;
}
@Override
public int requestFusion(int mode) {
if ((mode & QueueDisposable.ASYNC) != 0) {
sourceMode = QueueDisposable.ASYNC;
return QueueDisposable.ASYNC;
}
return 0;
}
@Nullable
@Override
public T poll() throws Exception {
return queue.poll();
}
@Override
public boolean isEmpty() {
return queue.isEmpty();
}
@Override
public void clear() {
queue.clear();
}
}
}
在 subscribeActual()
方法中,会创建一个 ObserveOnObserver
对象,并使用调度器的 createWorker()
方法创建一个工作线程。当 Observable
发射数据时,ObserveOnObserver
的 onNext()
、onError()
和 onComplete()
方法会将数据或事件放入队列,并调用 schedule()
方法安排任务在指定线程执行。schedule()
方法会调用工作线程的 schedule()
方法,将 ObserveOnObserver
作为一个 Runnable
任务提交到指定线程执行。
五、调度器的实现细节
5.1 IoScheduler 实现细节
IoScheduler
是用于处理 I/O 密集型任务的调度器,它使用一个线程池来管理线程。以下是 IoScheduler
的部分源码:
public final class IoScheduler extends Scheduler {
// 线程池管理器
private final CachedWorkerPool pool;
// 线程名称前缀
private static final String WORKER_NAME_PREFIX = "RxCachedThreadScheduler";
// 线程工厂
private static final ThreadFactory THREAD_FACTORY = new RxThreadFactory(WORKER_NAME_PREFIX);
public IoScheduler() {
// 初始化线程池管理器
this.pool = new CachedWorkerPool(60, TimeUnit.SECONDS, THREAD_FACTORY);
}
@Override
public Worker createWorker() {
// 创建一个工作线程
return new EventLoopWorker(pool.get());
}
static final class EventLoopWorker extends Scheduler.Worker {
private final CompositeDisposable tasks;
private final CachedWorkerPool pool;
private final ThreadWorker threadWorker;
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.tasks = new CompositeDisposable();
this.threadWorker = pool.get();
}
@Override
public Disposable schedule(Runnable action, long delayTime, TimeUnit unit) {
if (tasks.isDisposed()) {
// 工作线程已销毁,直接返回一个已销毁的 Disposable
return Disposables.disposed();
}
// 调用线程工作器的 schedule() 方法安排任务执行
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
@Override
public void dispose() {
if (!tasks.isDisposed()) {
// 标记任务集合为已销毁
tasks.dispose();
// 将线程工作器返回到线程池
pool.release(threadWorker);
}
}
@Override
public boolean isDisposed() {
return tasks.isDisposed();
}
}
static final class ThreadWorker extends NewThreadWorker {
ThreadWorker(ThreadFactory threadFactory) {
super(threadFactory);
}
}
static final class CachedWorkerPool implements Runnable {
private final long keepAliveTime;
private final ConcurrentLinkedQueue<ThreadWorker> expiringWorkerQueue;
private final CompositeDisposable allWorkers;
private final ScheduledExecutorService evictorService;
private final Future<?> evictorTask;
private final ThreadFactory threadFactory;
CachedWorkerPool(long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) {
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.expiringWorkerQueue = new ConcurrentLinkedQueue<ThreadWorker>();
this.allWorkers = new CompositeDisposable();
this.threadFactory = threadFactory;
ScheduledExecutorService evictor = null;
Future<?> task = null;
if (keepAliveTime > 0) {
evictor = Executors.newScheduledThreadPool(1, new RxThreadFactory("RxCachedWorkerPoolEvictor"));
task = evictor.scheduleWithFixedDelay(this, keepAliveTime, keepAliveTime, TimeUnit.NANOSECONDS);
}
evictorService = evictor;
evictorTask = task;
}
ThreadWorker get() {
if (allWorkers.isDisposed()) {
return SHUTDOWN_THREAD_WORKER;
}
while (!expiringWorkerQueue.isEmpty()) {
ThreadWorker threadWorker = expiringWorkerQueue.poll();
if (threadWorker != null) {
return threadWorker;
}
}
// 创建一个新的线程工作器
ThreadWorker w = new ThreadWorker(threadFactory);
allWorkers.add(w);
return w;
}
void release(ThreadWorker threadWorker) {
// 设置线程工作器的最后活动时间
threadWorker.setExpirationTime(now() + keepAliveTime);
expiringWorkerQueue.offer(threadWorker);
}
@Override
public void run() {
trimExpiredWorkers();
}
void trimExpiredWorkers() {
if (!expiringWorkerQueue.isEmpty()) {
long currentTimestamp = now();
for (ThreadWorker threadWorker : expiringWorkerQueue) {
if (threadWorker.getExpirationTime() <= currentTimestamp) {
if (expiringWorkerQueue.remove(threadWorker)) {
allWorkers.remove(threadWorker);
}
}
}
}
}
long now() {
return System.nanoTime();
}
}
}
IoScheduler
的构造函数中会创建一个 CachedWorkerPool
实例,用于管理线程池。createWorker()
方法会创建一个 EventLoopWorker
对象,该对象负责执行具体的任务。EventLoopWorker
内部包含一个 ThreadWorker
对象,它继承自 NewThreadWorker
,用于实际执行任务。
CachedWorkerPool
负责线程的缓存和回收。当需要一个线程时,会先从 expiringWorkerQueue
中查找可用的线程,如果没有则创建一个新的线程。当线程不再使用时,会将其返回到 expiringWorkerQueue
中,并设置一个过期时间。evictorService
会定期检查 expiringWorkerQueue
中的线程,将过期的线程移除。
5.2 ComputationScheduler 实现细节
ComputationScheduler
是用于处理 CPU 密集型任务的调度器,它的线程池大小通常与 CPU 核心数相同。以下是 ComputationScheduler
的部分源码:
public final class ComputationScheduler extends Scheduler {
// 线程名称前缀
private static final String WORKER_NAME_PREFIX = "RxComputationThreadPool";
// 线程工厂
private static final ThreadFactory THREAD_FACTORY = new RxThreadFactory(WORKER_NAME_PREFIX);
// 最大线程数
private static final int MAX_THREADS;
// 工作线程数组
private final AtomicInteger index;
private final Worker[] workers;
static {
// 获取系统属性中指定的最大线程数,如果未指定则使用 CPU 核心数
MAX_THREADS = Integer.getInteger("rx2.computation-threads", Runtime.getRuntime().availableProcessors());
}
public ComputationScheduler() {
this(THREAD_FACTORY);
}
public ComputationScheduler(ThreadFactory threadFactory) {
index = new AtomicInteger();
workers = new Worker[MAX_THREADS];
for (int i = 0; i < MAX_THREADS; i++) {
// 初始化工作线程数组
workers[i] = new EventLoopWorker(threadFactory);
}
}
@Override
public Worker createWorker() {
// 循环选择一个工作线程
return workers[Math.abs(index.getAndIncrement() % MAX_THREADS)];
}
static final class EventLoopWorker extends Scheduler.Worker {
private final CompositeDisposable tasks;
private final ScheduledExecutorService executor;
EventLoopWorker(ThreadFactory threadFactory) {
this.tasks = new CompositeDisposable();
// 创建一个单线程的定时执行器
this.executor = Executors.newScheduledThreadPool(1, threadFactory);
try {
// 设置线程池的拒绝策略
((ThreadPoolExecutor) executor).setKeepAliveTime(60, TimeUnit.SECONDS);
((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true);
} catch (ClassCastException e) {
// 忽略异常
}
}
@Override
public Disposable schedule(Runnable action, long delayTime, TimeUnit unit) {
if (tasks.isDisposed()) {
// 工作线程已销毁,直接返回一个已销毁的 Disposable
return Disposables.disposed();
}
// 创建一个 ScheduledRunnable 任务
ScheduledRunnable scheduledRunnable = new ScheduledRunnable(action, tasks);
tasks.add(scheduledRunnable);
// 安排任务在指定延迟后执行
Future<?> future;
try {
if (delayTime <= 0) {
future = executor.submit(scheduledRunnable);
} else {
future = executor.schedule(scheduledRunnable, delayTime, unit);
}
scheduledRunnable.setFuture(future);
} catch (RejectedExecutionException e) {
tasks.remove(scheduledRunnable);
RxJavaPlugins.onError(e);
}
return scheduledRunnable;
}
@Override
public void dispose() {
if (!tasks.isDisposed()) {
// 标记任务集合为已销毁
tasks.dispose();
// 关闭执行器
executor.shutdownNow();
}
}
@Override
public boolean isDisposed() {
return tasks.isDisposed();
}
}
}
ComputationScheduler
的构造函数中会初始化一个大小为 MAX_THREADS
的工作线程数组。createWorker()
方法会循环选择一个工作线程来执行任务。
EventLoopWorker
内部包含一个 ScheduledExecutorService
,用于执行定时任务。schedule()
方法会将任务包装成 ScheduledRunnable
对象,并提交给 ScheduledExecutorService
执行。
5.3 SingleScheduler 实现细节
SingleScheduler
是使用一个单线程来执行任务的调度器,任务会按顺序依次执行。以下是 SingleScheduler
的部分源码:
public final class SingleScheduler extends Scheduler {
// 线程名称前缀
private static final String WORKER_NAME_PREFIX = "RxSingleScheduler";
// 线程工厂
private static final ThreadFactory THREAD_FACTORY = new RxThreadFactory(WORKER_NAME_PREFIX);
// 单例的工作线程
private final ScheduledExecutorService executor;
public SingleScheduler() {
// 创建一个单线程的定时执行器
this.executor = Executors.newScheduledThreadPool(1, THREAD_FACTORY);
try {
// 设置线程池的拒绝策略
((ThreadPoolExecutor) executor).setKeepAliveTime(60, TimeUnit.SECONDS);
((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true);
} catch (ClassCastException e) {
// 忽略异常
}
}
@Override
public Worker createWorker() {
// 创建一个单线程工作器
return new SingleWorker(executor);
}
static final class SingleWorker extends Scheduler.Worker {
private final CompositeDisposable tasks;
private final ScheduledExecutorService executor;
SingleWorker(ScheduledExecutorService executor) {
this.tasks = new CompositeDisposable();
this.executor = executor;
}
@Override
public Disposable schedule(Runnable action, long delayTime, TimeUnit unit) {
if (tasks.isDisposed()) {
// 工作线程已销毁,直接返回一个已销毁的 Disposable
return Disposables.disposed();
}
// 创建一个 ScheduledRunnable 任务
ScheduledRunnable scheduledRunnable = new ScheduledRunnable(action, tasks);
tasks.add(scheduledRunnable);
// 安排任务在指定延迟后执行
Future<?> future;
try {
if (delayTime <= 0) {
future = executor.submit(scheduledRunnable);
} else {
future = executor.schedule(scheduledRunnable, delayTime, unit);
}
scheduledRunnable.setFuture(future);
} catch (RejectedExecutionException e) {
tasks.remove(scheduledRunnable);
RxJavaPlugins.onError(e);
}
return scheduledRunnable;
}
@Override
public void dispose() {
if (!tasks.isDisposed()) {
// 标记任务集合为已销毁
tasks.dispose();
}
}
@Override
public boolean isDisposed() {
return tasks.isDisposed();
}
}
}
SingleScheduler
的构造函数中会创建一个单线程的 ScheduledExecutorService
。createWorker()
方法会创建一个 SingleWorker
对象,该对象负责执行具体的任务。SingleWorker
的 schedule()
方法会将任务包装成 ScheduledRunnable
对象,并提交给 ScheduledExecutorService
执行。
六、线程调度的实际应用场景
6.1 网络请求
在 Android 开发中,网络请求通常是一个耗时操作,不能在主线程中执行。可以使用 RxJava 的线程调度模块将网络请求放在 I/O 线程中执行,将结果更新 UI 的操作放在主线程中执行。
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
// 定义 API 接口
interface ApiService {
@GET("data")
Observable<Data> getData();
}
// 数据类
class Data {
// 数据字段
}
public class NetworkRequestExample {
public static void main(String[] args) {
// 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
// 创建 API 服务实例
ApiService apiService = retrofit.create(ApiService.class);
// 发起网络请求
apiService.getData()
.subscribeOn(Schedulers.io()) // 指定网络请求在 I/O 线程执行
.observeOn(AndroidSchedulers.mainThread()) // 指定结果处理在主线程执行
.subscribe(data -> {
// 处理返回的数据
System.out.println("Received data: " + data);
}, error -> {
// 处理错误
System.out.println("Error: " + error.getMessage());
});
}
}
在上述代码中,subscribeOn(Schedulers.io())
表示网络请求操作将在 I/O 线程中执行,observeOn(AndroidSchedulers.mainThread())
表示结果处理操作将在主线程中执行,这样可以避免在主线程中进行耗时的网络请求,从而保证 UI 的流畅性。
6.2 数据处理
在数据处理场景中,可能需要进行大量的计算或文件读写操作,这些操作会占用较多的 CPU 资源。可以使用 Schedulers.computation()
调度器将数据处理任务放在计算线程中执行,避免阻塞主线程。
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
public class DataProcessingExample {
public static void main(String[] args) {
// 创建一个 Observable 发射一系列整数
Observable<Integer> numbers = Observable.range(1, 10);
// 对每个
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
public class DataProcessingExample {
public static void main(String[] args) {
// 创建一个 Observable 发射一系列整数
Observable<Integer> numbers = Observable.range(1, 10);
// 对每个数字进行平方运算,并打印结果
numbers.subscribeOn(Schedulers.computation()) // 指定数据处理在计算线程执行
.map(num -> {
// 模拟耗时的数据处理操作
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return num * num;
})
.observeOn(Schedulers.single()) // 指定结果打印在单线程执行
.subscribe(result -> {
System.out.println("Result: " + result);
}, error -> {
System.out.println("Error: " + error.getMessage());
});
// 为了让程序有足够时间执行,主线程休眠一段时间
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,subscribeOn(Schedulers.computation())
将 map
操作符中的数据处理任务放在计算线程中执行。map
操作符对每个发射的数字进行平方运算,并且模拟了一个耗时的操作(Thread.sleep(100)
)。由于使用了 Schedulers.computation()
,这个耗时的计算不会阻塞主线程。
接着,observeOn(Schedulers.single())
指定结果的打印操作在单线程中执行。这样可以保证结果按顺序依次打印,避免多线程并发打印导致输出混乱。
6.3 文件读写
文件读写也是常见的 I/O 操作,会消耗一定的时间。可以使用 Schedulers.io()
调度器将文件读写任务放在 I/O 线程中执行,避免阻塞主线程。
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class FileReadingExample {
public static void main(String[] args) {
// 创建一个 Observable 来读取文件内容
Observable<String> fileContentObservable = Observable.create(emitter -> {
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
// 发射每一行内容
emitter.onNext(line);
}
// 完成发射
emitter.onComplete();
} catch (IOException e) {
// 发射错误
emitter.onError(e);
}
});
fileContentObservable.subscribeOn(Schedulers.io()) // 指定文件读取在 I/O 线程执行
.observeOn(Schedulers.single()) // 指定结果处理在单线程执行
.subscribe(line -> {
System.out.println("Read line: " + line);
}, error -> {
System.out.println("Error reading file: " + error.getMessage());
});
}
}
在上述代码中,Observable.create
创建了一个自定义的 Observable
,用于读取文件内容。subscribeOn(Schedulers.io())
确保文件读取操作在 I/O 线程中执行,避免阻塞主线程。observeOn(Schedulers.single())
保证结果处理(打印每一行内容)在单线程中按顺序执行。
6.4 定时任务
RxJava 可以很方便地实现定时任务,通过 Schedulers
可以指定定时任务执行的线程。
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import java.util.concurrent.TimeUnit;
public class TimerExample {
public static void main(String[] args) {
// 创建一个 Observable,延迟 2 秒后发射一个整数
Observable.timer(2, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io()) // 指定定时任务在 I/O 线程执行
.observeOn(Schedulers.single()) // 指定结果处理在单线程执行
.subscribe(result -> {
System.out.println("Timer fired after 2 seconds. Result: " + result);
}, error -> {
System.out.println("Error: " + error.getMessage());
});
// 为了让程序有足够时间执行,主线程休眠一段时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,Observable.timer(2, TimeUnit.SECONDS)
创建了一个延迟 2 秒后发射一个整数的 Observable
。subscribeOn(Schedulers.io())
指定定时任务在 I/O 线程中执行,observeOn(Schedulers.single())
指定结果处理在单线程中执行。
七、线程调度的注意事项
7.1 避免过度切换线程
频繁的线程切换会带来额外的开销,降低程序的性能。在使用 subscribeOn()
和 observeOn()
时,要根据实际需求合理安排线程调度,避免不必要的线程切换。
例如,下面的代码存在过度切换线程的问题:
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
public class OverThreadSwitchingExample {
public static void main(String[] args) {
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.map(num -> num * 2)
.observeOn(Schedulers.io())
.subscribe(result -> {
System.out.println("Result: " + result);
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在这个例子中,数据在 Schedulers.io()
和 Schedulers.computation()
之间来回切换,增加了不必要的开销。可以根据实际情况,尽量减少线程切换,例如:
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
public class OptimizedThreadSwitchingExample {
public static void main(String[] args) {
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.io())
.map(num -> num * 2)
.observeOn(Schedulers.io())
.subscribe(result -> {
System.out.println("Result: " + result);
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
7.2 正确处理异常
在不同线程中执行任务时,异常处理需要特别注意。如果在 subscribeOn()
指定的线程中抛出异常,可能不会被 Observer
正确捕获。因此,建议在 Observable
链中使用 onErrorResumeNext()
或 onErrorReturn()
等操作符来处理异常。
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
public class ExceptionHandlingExample {
public static void main(String[] args) {
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.io())
.map(num -> {
if (num == 2) {
// 模拟抛出异常
throw new RuntimeException("Error occurred");
}
return num * 2;
})
.onErrorResumeNext(throwable -> {
System.out.println("Caught exception: " + throwable.getMessage());
return Observable.just(-1);
})
.observeOn(Schedulers.single())
.subscribe(result -> {
System.out.println("Result: " + result);
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,onErrorResumeNext()
操作符捕获了 map
操作符中抛出的异常,并返回一个新的 Observable
,避免了异常导致整个流的终止。
7.3 资源管理
在使用不同的调度器时,要注意资源的管理。例如,Schedulers.io()
使用的线程池可能会创建大量的线程,如果不及时释放资源,可能会导致内存泄漏。
对于 Disposable
对象,要在不需要时及时调用 dispose()
方法来释放资源。例如:
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class ResourceManagementExample {
public static void main(String[] args) {
Observable<Long> intervalObservable = Observable.interval(1, java.util.concurrent.TimeUnit.SECONDS)
.subscribeOn(Schedulers.io());
Disposable disposable = intervalObservable.subscribe(result -> {
System.out.println("Received: " + result);
});
// 模拟一段时间后取消订阅
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 释放资源
disposable.dispose();
}
}
在上述代码中,intervalObservable
会每隔 1 秒发射一个整数。通过 Disposable
对象可以在不需要时取消订阅,释放资源。
八、源码中的线程安全与同步机制
8.1 调度器内部的线程安全
在 RxJava 的调度器实现中,很多地方都需要保证线程安全。例如,在 IoScheduler
的 CachedWorkerPool
中,expiringWorkerQueue
和 allWorkers
是共享资源,多个线程可能会同时对它们进行读写操作。
static final class CachedWorkerPool implements Runnable {
// 存储可复用的线程工作器的队列
private final ConcurrentLinkedQueue<ThreadWorker> expiringWorkerQueue;
// 存储所有线程工作器的集合
private final CompositeDisposable allWorkers;
// ... 其他代码 ...
ThreadWorker get() {
if (allWorkers.isDisposed()) {
return SHUTDOWN_THREAD_WORKER;
}
while (!expiringWorkerQueue.isEmpty()) {
// 从队列中取出一个线程工作器
ThreadWorker threadWorker = expiringWorkerQueue.poll();
if (threadWorker != null) {
return threadWorker;
}
}
// 如果队列为空,创建一个新的线程工作器
ThreadWorker w = new ThreadWorker(threadFactory);
allWorkers.add(w);
return w;
}
void release(ThreadWorker threadWorker) {
// 设置线程工作器的过期时间
threadWorker.setExpirationTime(now() + keepAliveTime);
// 将线程工作器放入队列
expiringWorkerQueue.offer(threadWorker);
}
// ... 其他代码 ...
}
expiringWorkerQueue
使用了 ConcurrentLinkedQueue
,它是线程安全的队列,多个线程可以同时进行入队和出队操作。allWorkers
是 CompositeDisposable
类型,它内部有自己的同步机制,保证在多线程环境下的操作安全。
8.2 任务调度中的同步
在任务调度过程中,也需要考虑同步问题。例如,在 ObservableSubscribeOn
中,SubscribeOnObserver
的 setDisposable()
方法需要保证线程安全。
static final class SubscribeOnObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable {
// ... 其他代码 ...
void setDisposable(Disposable d) {
// 使用 DisposableHelper.setOnce 方法保证原子性操作
DisposableHelper.setOnce(this, d);
}
// ... 其他代码 ...
}
DisposableHelper.setOnce()
方法使用了原子操作,确保 Disposable
对象只会被设置一次,避免多线程环境下的竞态条件。
8.3 线程间通信的同步
在不同线程之间传递数据和事件时,需要进行同步。例如,在 ObservableObserveOn
的 ObserveOnObserver
中,onNext()
方法会将数据放入队列,而 run()
方法会从队列中取出数据进行处理。
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
// 存储数据的队列
SimpleQueue<T> queue;
// 标记是否完成
volatile boolean done;
// 存储错误信息
Throwable error;
// 标记是否已销毁
volatile boolean disposed;
// 数据源模式
int sourceMode;
// ... 其他代码 ...
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
// 将数据放入队列
queue.offer(t);
}
// 安排任务执行
schedule();
}
@Override
public void run() {
if (disposed) {
return;
}
boolean canComplete = delayError || sourceMode != QueueDisposable.ASYNC;
SimpleQueue<T> q = queue;
Observer<? super T> a = actual;
int missed = 1;
for (; ; ) {
if (checkTerminated(done, q.isEmpty(), a, canComplete)) {
return;
}
for (; ; ) {
boolean d = done;
T v;
try {
// 从队列中取出数据
v = q.poll();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
worker.dispose();
return;
}
boolean empty = v == null;
if (checkTerminated(d, empty, a, canComplete)) {
return;
}
if (empty) {
break;
}
// 处理数据
a.onNext(v);
}
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
// ... 其他代码 ...
}
queue
作为线程间通信的媒介,需要保证在多线程环境下的读写安全。在 onNext()
方法中,将数据放入队列,在 run()
方法中从队列中取出数据进行处理。同时,使用 done
、error
和 disposed
等标志位来协调不同线程之间的操作,确保数据的正确处理。
九、RxJava 线程调度模块的扩展与定制
9.1 自定义调度器
在某些特定的场景下,RxJava 提供的内置调度器可能无法满足需求,这时可以自定义调度器。自定义调度器需要继承 Scheduler
类,并实现相应的方法。
import io.reactivex.Scheduler;
import io.reactivex.disposables.Disposable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 自定义调度器类
public class CustomScheduler extends Scheduler {
// 线程池执行器
private final ExecutorService executorService;
// 构造函数,初始化线程池
public CustomScheduler(int threadCount) {
// 创建一个固定大小的线程池
this.executorService = Executors.newFixedThreadPool(threadCount);
}
@Override
public Worker createWorker() {
// 创建一个自定义的工作线程
return new CustomWorker(executorService);
}
// 自定义工作线程类
private static class CustomWorker extends Scheduler.Worker {
// 线程池执行器
private final ExecutorService executorService;
// 标记是否已销毁
private volatile boolean disposed;
// 构造函数,传入线程池执行器
CustomWorker(ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public Disposable schedule(Runnable action, long delayTime, java.util.concurrent.TimeUnit unit) {
if (disposed) {
return Disposables.disposed();
}
// 创建一个调度任务
ScheduledRunnable scheduledRunnable = new ScheduledRunnable(action);
if (delayTime <= 0) {
// 立即执行任务
executorService.submit(scheduledRunnable);
} else {
// 延迟执行任务
executorService.schedule(scheduledRunnable, delayTime, unit);
}
return scheduledRunnable;
}
@Override
public void dispose() {
// 标记为已销毁
disposed = true;
// 关闭线程池
executorService.shutdown();
}
@Override
public boolean isDisposed() {
return disposed;
}
}
// 调度任务类
private static class ScheduledRunnable implements Runnable, Disposable {
// 要执行的任务
private final Runnable action;
// 标记是否已销毁
private volatile boolean disposed;
// 构造函数,传入要执行的任务
ScheduledRunnable(Runnable action) {
this.action = action;
}
@Override
public void run() {
if (!disposed) {
// 执行任务
action.run();
}
}
@Override
public void dispose() {
// 标记为已销毁
disposed = true;
}
@Override
public boolean isDisposed() {
return disposed;
}
}
}
使用自定义调度器的示例:
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
public class CustomSchedulerExample {
public static void main(String[] args) {
// 创建自定义调度器,使用 3 个线程
CustomScheduler customScheduler = new CustomScheduler(3);
// 创建一个 Observable 发射一系列整数
Observable.just(1, 2, 3)
.subscribeOn(customScheduler) // 指定使用自定义调度器
.subscribe(result -> {
System.out.println("Result: " + result + " on thread: " + Thread.currentThread().getName());
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,CustomScheduler
继承自 Scheduler
类,并重写了 createWorker()
方法,返回一个自定义的 CustomWorker
实例。CustomWorker
实现了任务的调度和资源管理。ScheduledRunnable
是一个包装类,用于包装要执行的任务,并实现了 Disposable
接口,方便进行资源管理。
9.2 自定义调度器的应用场景
自定义调度器可以应用于各种特定的场景,例如:
9.2.1 限制并发数
在某些情况下,可能需要限制同时执行的任务数量。可以通过自定义调度器,使用固定大小的线程池来实现并发数的限制。
9.2.2 特定的线程命名规则
在调试和监控时,线程的命名可以帮助我们更好地理解程序的执行流程。可以通过自定义调度器,为线程设置特定的命名规则。
9.2.3 与第三方线程池集成
如果项目中已经使用了第三方的线程池管理工具,例如 Hystrix
或 ForkJoinPool
,可以通过自定义调度器将 RxJava 的任务调度与第三方线程池集成。
十、总结与展望
10.1 总结
RxJava 的线程调度模块为开发者提供了强大而灵活的异步编程能力。通过调度器(Scheduler
)和 subscribeOn()
、observeOn()
方法,开发者可以轻松地控制任务在不同线程上的执行,实现多线程编程和异步操作。
- 调度器类型丰富:RxJava 提供了多种内置调度器,如
Schedulers.io()
用于 I/O 密集型任务、Schedulers.computation()
用于 CPU 密集型任务、Schedulers.single()
用于单线程执行任务等,满足了不同场景的需求。 - 线程切换灵活:
subscribeOn()
方法用于指定Observable
发射数据的线程,observeOn()
方法用于指定Observer
接收数据的线程,并且observeOn()
可以在链式调用中多次使用,实现灵活的线程切换。 - 源码实现精巧:从源码层面来看,调度器的实现涉及到线程池管理、任务调度、线程安全等多个方面的知识。例如,
IoScheduler
使用CachedWorkerPool
来管理线程池,实现线程的复用和回收;ObservableSubscribeOn
和ObservableObserveOn
类负责处理线程调度的具体逻辑。
10.2 展望
随着软件开发的不断发展,RxJava 的线程调度模块也有一些可以改进和拓展的方向。
10.2.1 更好的性能优化
虽然 RxJava 已经在性能方面做了很多优化,但在高并发、大数据量的场景下,仍然可能存在性能瓶颈。未来可以进一步优化调度器的实现,减少线程切换的开销,提高任务调度的效率。
10.2.2 与新的编程范式融合
随着响应式编程、异步编程等新的编程范式的不断发展,RxJava 可以更好地与这些范式融合,提供更加简洁、高效的编程接口。例如,与 Kotlin 的协程结合,实现更加流畅的异步编程体验。
10.2.3 增强调试和监控能力
在复杂的异步程序中,调试和监控是比较困难的。未来可以增强 RxJava 的调试和监控能力,例如提供更详细的日志信息、可视化的线程调度图等,帮助开发者更好地理解和优化程序。
10.2.4 支持更多的平台和环境
随着移动开发、物联网等领域的发展,RxJava 可以进一步扩展对不同平台和环境的支持,例如在嵌入式系统、分布式系统中提供更好的性能和兼容性。
总之,RxJava 的线程调度模块是一个非常强大和实用的工具,通过深入理解其原理和源码,开发者可以更好地利用它来实现高效、稳定的异步编程。同时,随着技术的不断发展,RxJava 也有望在未来不断完善和发展,为开发者带来更多的便利和惊喜。