从原理上搞懂如何设置线程池参数大小?
Posted 石杉的架构笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从原理上搞懂如何设置线程池参数大小?相关的知识,希望对你有一定的参考价值。
扫描下方海报了解专栏详情
本文来源:Java后端技术栈
《Java工程师面试突击(第3季)》重磅升级,由原来的70讲增至160讲,内容扩充一倍多,升级部分内容请参见文末
-
线程池的线程数量设置过多会导致线程竞争激烈 -
如果线程数量设置过少的话,还会导致系统无法充分利用计算机资源
线程池原理
线程池框架 Executor
我建议你使用 ThreadPoolExecutor 自我定制一套线程池(阿里规范中也是建议不要使用 Executors 创建线程池,建议使用ThreadPoolExecutor 来创建线程池)。
corePoolSize
:线程池的核心线程数量maximumPoolSize
:线程池的最大线程数keepAliveTime
:当线程数大于核心线程数时,多余的空闲线程存活的最长时间unit
:时间单位workQueue
:任务队列,用来储存等待执行任务的队列threadFactory
:线程工厂,用来创建线程,一般默认即可handler
:拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
计算线程数量
这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。
一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。
public class CPUTypeTest implements Runnable {
// 整体执行时间,包括在队列中等待的时间
List<Long> wholeTimeList;
// 真正执行时间
List<Long> runTimeList;
private long initStartTime = 0;
/**
* 构造函数
* @param runTimeList
* @param wholeTimeList
*/
public CPUTypeTest(List<Long> runTimeList, List<Long> wholeTimeList) {
initStartTime = System.currentTimeMillis();
this.runTimeList = runTimeList;
this.wholeTimeList = wholeTimeList;
}
/**
* 判断素数
* @param number
* @return
*/
public boolean isPrime(final int number) {
if (number <= 1)
return false;
for (int i = 2; i <= Math.sqrt(number); i++) {
if (number % i == 0)
return false;
}
return true;
}
/**
* 計算素数
* @param number
* @return
*/
public int countPrimes(final int lower, final int upper) {
int total = 0;
for (int i = lower; i <= upper; i++) {
if (isPrime(i))
total++;
}
return total;
}
public void run() {
long start = System.currentTimeMillis();
countPrimes(1, 1000000);
long end = System.currentTimeMillis();
long wholeTime = end - initStartTime;
long runTime = end - start;
wholeTimeList.add(wholeTime);
runTimeList.add(runTime);
System.out.println(" 单个线程花费时间:" + (end - start));
}
}
测试代码在 4 核 intel i5 CPU 机器上的运行时间变化如下:
这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 2N。
public class IOTypeTest implements Runnable {
// 整体执行时间,包括在队列中等待的时间
Vector<Long> wholeTimeList;
// 真正执行时间
Vector<Long> runTimeList;
private long initStartTime = 0;
/**
* 构造函数
* @param runTimeList
* @param wholeTimeList
*/
public IOTypeTest(Vector<Long> runTimeList, Vector<Long> wholeTimeList) {
initStartTime = System.currentTimeMillis();
this.runTimeList = runTimeList;
this.wholeTimeList = wholeTimeList;
}
/**
*IO 操作
* @param number
* @return
* @throws IOException
*/
public void readAndWrite() throws IOException {
File sourceFile = new File("D:/test.txt");
// 创建输入流
BufferedReader input = new BufferedReader(new FileReader(sourceFile));
// 读取源文件, 写入到新的文件
String line = null;
while((line = input.readLine()) != null){
//System.out.println(line);
}
// 关闭输入输出流
input.close();
}
public void run() {
long start = System.currentTimeMillis();
try {
readAndWrite();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long end = System.currentTimeMillis();
long wholeTime = end - initStartTime;
long runTime = end - start;
wholeTimeList.add(wholeTime);
runTimeList.add(runTime);
System.out.println(" 单个线程花费时间:" + (end - start));
}
}
WT(线程等待时间)= 36788ms [线程运行总时间] - 36788ms[ST(线程时间运行时间)]= 0
线程数 =N(CPU 核数)*(1+ 0 [WT(线程等待时间)]/36788ms[ST(线程时间运行时间)])= N(CPU 核数)
这跟我们之前通过 CPU 密集型的计算公式 N+1 所得出的结果差不多。
总结
END
《Java工程师面试突击第三季》加餐部分大纲:(注:1-66讲的大纲请扫描文末二维码,在课程详情页获取)
详细的课程内容,大家可以扫描下方二维码了解:
以上是关于从原理上搞懂如何设置线程池参数大小?的主要内容,如果未能解决你的问题,请参考以下文章