Java动态修改线程数_线程池核心线程数为什么设置为 N+1

Question: 为什么要设置线程池的大小?又或者这个问题的主要切入点又是什么呢?

答:为了提高 CPU 的利用率,为了提高 CPU 的利用率,为了提高 CPU 的利用率。

重要的事情说三遍!!!

提高到多少才算好呢?当然是 100% 了。当我们从这个角度去考虑的话,一切都会变得明朗起来。

线程池的理想大小 取决于提交任务的类型以及所部署系统的特性,您可千万不要傻傻的写类似这样的语句。

private static final int CORE_SIZE = 5;//非常不建议这么写

我们不应该在代码中固定线程池的大小,而应该通过某种配置机制提供,或者根据 Runtime.availableProcess() 来动态计算。

如何计算线程池大小

我们要根据任务是 计算密集型 or I/O密集型 来设置线程池的大小。计算密集型是指处理这种任务时,线程不会发生阻塞,线程不阻塞就一定程度代表 CPU 一直在忙碌;I/O 密集型 是指运行该类任务时线程多会发生阻塞,一旦阻塞,CPU 就多被闲置,浪费 CPU 资源。

对于计算密集型的任务,在有N 个处理器的系统上,当线程池的大小为 N+1 时,能实现 CPU 的最优利用率。(即使当计算密集型的线程 偶尔由于页缺失故障或者其他原因暂停时,这个“额外” 的线程也能确保CPU 的时装周期不会被浪费。)

对于 I/O 操作或其他 阻塞任务,由于线程并不会一直执行,因此线程池的规模应该更大。

计算公式一

所以为了正确设置线程池的大小,我们应该计算出 我们的计算型任务(用 C表示)占总任务的比例(总任务个数=计算型任务个数+阻塞型任务个数(用W表示))

假设当前 CPU 的核数 为 N = 4。

rate = C/(C+W)

这样 CORE_SIZE = N/rate。

如 当前有8个计算型任务,2个阻塞型任务,比例就是 0.8,也就是4/5,

计算可得 CORE_SIZE = 5 时,能最大程度的利用 CPU。

计算公式二(抄自 Java 并发编程实战)

171e51e13129

微信图片_20190411222257.png

其实上述两种方式结果是一样的。公式 2 还多了一个target CPU utilization ,代表目标cpu的使用率,比如我有8个核,但我只想分配4个核给线程池用,所以多了一个这个参数,总体来说不影响对所讲概念的理解。

Android AsyncTask 中又是如何设置的呢?

来看下 Android 8.0 版本源码。

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

// We want at least 2 threads and at most 4 threads in the core pool,

// preferring to have 1 less than the CPU count to avoid saturating

// the CPU with background work

private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));

private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

什么?我没看错吧,怎么是 CPU_COUNT - 1 ?还要将结果与 4 比较取一个最小值?

源码有解释的:之所以 减掉这个1,是因为为了避免后台任务将 CPU 资源完全耗尽, 减掉的这个1 是留给我们 主线程 使用的。

参考文章

《Java 并发编程实战》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值