RxJava2中Schedulers.io()与computation()高并发IO场景选型及线程池配置疑问
咱们先直接说结论:你的场景必须用Schedulers.io(),绝对不能选Schedulers.computation(),下面给你拆解原因,再解答你关于线程池大小的疑问。
为什么选Schedulers.io()?
你这里的核心任务是调用其他服务的IO操作——这类任务的特点是大部分时间都在等待(等网络响应、等外部服务返回),实际占用CPU的时间很少。
Schedulers.computation()是专门给CPU密集型任务设计的,它的线程池大小默认等于你的CPU核心数(比如8核机器就是8个线程)。你想想,500个并发请求每个要生成10个IO任务,总共是5000个任务,用只有8个线程的computation调度器,所有任务都会挤在队列里排队,完全发挥不出吞吐量,系统会慢到爆炸。
而Schedulers.io()就是为IO密集型场景量身打造的:它的线程池是弹性的,会根据任务量动态创建线程,空闲线程超过60秒会自动回收。你担心的“可能创建大量线程”其实不用太焦虑——因为IO任务大多处于等待状态,这些线程占用的CPU和内存资源都非常有限,哪怕有几百个线程,也不会对系统造成太大负担,反而能让所有IO任务及时得到处理,不会因为排队拖慢整体响应。
能不能指定线程池大小?
关于Schedulers.computation()
默认的computation调度器线程池大小是固定的(等于CPU核心数),RxJava没有提供直接修改默认computation线程池大小的API——这其实是合理的,因为CPU密集型任务用超过核心数的线程会导致频繁的上下文切换,反而降低性能。
如果你非要自定义(非常不建议这么做,违背设计初衷),可以自己创建一个固定大小的线程池,再用Schedulers.from(Executor)包装成自定义调度器:
// 比如强行把computation线程池改成16个线程 Executor customComputationExecutor = Executors.newFixedThreadPool(16); Scheduler customComputationScheduler = Schedulers.from(customComputationExecutor);
关于Schedulers.io()
默认的io调度器是无界弹性线程池,但你完全可以自定义线程池的参数(核心线程数、最大线程数、空闲回收时间等),来避免线程无限制增长。比如针对你的500并发+每个请求10个IO的场景,你可以这样创建自定义io调度器:
ThreadPoolExecutor customIoThreadPool = new ThreadPoolExecutor( 100, // 核心线程数:保持100个常驻线程 500, // 最大线程数:最多允许创建500个线程 60L, TimeUnit.SECONDS, // 空闲线程60秒后回收 new LinkedBlockingQueue<>() // 任务队列 ); Scheduler customIoScheduler = Schedulers.from(customIoThreadPool);
这样既保证了任务能及时被处理,又不会让线程数疯长到失控。
最后再划个重点
- 你的IO密集型场景,
Schedulers.io()是唯一合理的选择,自定义线程池参数可以解决你对“大量线程”的顾虑。 - 别碰
Schedulers.computation()处理IO任务,那是给自己挖坑。 - 自定义调度器的核心是用
Schedulers.from(Executor)包装你自己配置的线程池。
内容的提问来源于stack exchange,提问作者Ankit Bansal

