java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java线程池参数自定义

java线程池参数自定义设置详解

作者:zhongh Jim

这篇文章主要为大家介绍了java线程池参数自定义设置详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

上一篇线程池+ FutureTask异步执行多任务只介绍了怎么搭配使用线程池,但没有说明里面的线程池的参数是怎么设置的,那么本文就说明一下。

这里把上篇文章的线程池参数设置贴出来:

//给这个接口的线程池定义里边的线程名字
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-start-runner-%d").build();
ExecutorService taskExe= new ThreadPoolExecutor(10,20,800L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(100),namedThreadFactory);

这些参数也不都是随意设置的,而是有一定的考量思路,下面会一 一介绍

先介绍一下线程池的构造函数

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    ...
}

我们创建线程池一般是手动设置线程池的参数,已经不建议使用Executors的FixedThreadPool 、SingleThreadPool、CachedThreadPool了

因为:

设置线程池参数需要参考几个数值:

tasks:每秒任务数,运维反馈是平均每秒 38个

taskcost:每个任务花费时间,0.2s

(3) responsetime:系统容忍(线程等待最长时间)的最大时间1s

corePoolSize:核心线程数

核心线程会一直存活,不管空不空闲,但如果设置了setAllowCoreThreadTimeout(true)会让核心线程在空闲超时后关闭

计算方式:corePoolSize=tasks/(1/taskcost) =tasks * taskcost =38*0.2=7.6 个

查阅了下文章,大佬说计算密集型(遍历+判断的逻辑耗时占比多)的接口可将核心线程设置为:

corePoolSize=CPU核数+1 =8+1=9,设置为10就好了

如何查看CPU核数:

System.out.println(Runtime.getRuntime().availableProcessors());

设置得稍微大一点,也能减少频繁创建额外线程带来的开销

maxPoolSize:最大线程数

如果核心线程数不够用,会创建额外的线程来执行任务。

创建额外线程的条件(缺一不可):

最大线程数我们设置的相对随意了些, 令maxPoolSize= 2* corePoolSize=20,大概能应对突然暴增的业务查询请求

keepAliveTime额外线程的可空闲时间

额外线程就是在核心线程数的基础上 另外创建的线程

额外线程空闲了keepAliveTime的时间后,线程退出,直至现有的线程数量=corePoolSize核心线程数

workQueue任务队列

常见的有3种:

(1) 无限队列LinkedBlockingQueue()

构造函数是new LinkedBlockingQueue<Runnable>()

允许的任务等待队列的最大长度为:Integer.MAX_VALUE,即能无限的接收新的任务,任何的拒绝策略也差不多没有意义了

另外,maximumPoolSize这个参数也没有意义了,因为只有同时满足 核心线程数量够了 + 任务队列workQueue满了 + 现有的线程数<maximumPoolSize最大线程数,才会去创建额外的线程

那咱们就不用这个队列了吧

(2) 有界队列

我们的任务基本的执行顺序基本也是先进先出,直接用了new LinkedBlockingQueue(int capacity),把容量设置得大一点,那样就不会轻易的填满队列导致频繁地创建额外的线程,减少线程频繁切换

(3) SynchronousQueue

new SynchronousQueue():队列长度为0,要添加新任务必须得有空闲的线程才能添加,因此要求 maximumPoolSize尽可能的大,还得 配置拒绝策略

最终, 我们选择了new LinkedBlockingQueue(int capacity)作为任务队列

任务队列的长度

queueCapacity = (coreSize/taskcost) * responsetime=8/0.2*1=80,队列长度设置为100也可

RejectedExecutionHandler拒绝策略

我们选择了默认的AbortPolicy抛异常:

抛异常的话,需要上游系统截获异常,并告知用户请求繁忙稍等一下

如果是DiscardPolicy丢任务的话我猜大概率是用户得不到响应吧,没这么搞过

线程工厂

它还是很有必要设置的,因为系统的线程池不止一个,不设置一下线程工厂,不给线程定义个名字的话,很难看到是哪个线程池的线程在跑,因为线程的名字都被写死成pool-1-thread-1pool-1-thread-2pool-2-thread-1

那么,问题来了:如何判断线程池里边的指定线程是否在执行任务?

更多关于线程池参数自定义的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文