线程池核心参数
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit,//时间单位
BlockingQueue workQueue,//任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler) //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
我们还可以通过下面这张图来了解下线程池中各个参数的相互关系:
- corePoolSize设置:线程数=N(CPU核数)*(1+WT(线程等待时间)/ST(线程时间运行时间)),
简单分类就是cpu密集型,设置为N+1,io密集型,设置为2N
我们可以通过JDK自带的工具VisualVM来查看WT/ST比例,以下例子是基于运行纯CPU运算的例子,我们可以看到:
WT(线程等待时间)= 36788ms [线程运行总时间] - 36788ms[ST(线程时间运行时间)]= 0
线程数=N(CPU核数)*(1+ 0 [WT(线程等待时间)]/36788ms[ST(线程时间运行时间)])= N(CPU核数)
这跟我们之前通过CPU密集型的计算公式N+1所得出的结果差不多。
-
等待队列大小:
1.CPU密集型,将queueCapacity调大一些,减少线程上下文切换时间(因为核心线程池中的任务很快就能执行完,不妨等待一下)
2.IO密集型,将queueCapacity调小一些,避免线程池不满但是任务却一直不执行的诡异现象
等待队列的设置非常关键 -
maximumPoolSize设置:主要根据系统资源
-
keepAliveTime 参数定义了非核心线程(即超出 corePoolSize 的线程)在空闲时可以存活多久。设置 keepAliveTime 的值时,应考虑以下因素:
1.任务的频率和大小
如果你的应用程序经常接收到突发的大量任务,但在两次突发之间有较长的空闲时间,你可能希望设置较长的 keepAliveTime,以便保留一些线程,避免在下一次突发时重新创建线程。
相反,如果任务到达的频率很高,且任务规模较小,可以设置较短的 keepAliveTime,以便在任务完成后尽快释放不需要的资源。
2.系统资源
如果系统资源(特别是内存)比较紧张,可以设置较短的 keepAliveTime,以便更快地回收不活跃的线程所占用的资源。