最近一直在研究线程池的使用原理,做过开发的同事都知道,要设置合理的线程池需要考虑的因素太多,特别是高并发情况下,如果
不合理的设置线程池数量,有可能会导致生产上面出现各种问题,比如cpu内存飙升,报线程池拒绝策略等等。那么,怎么来合理设置线程池
大小呢?这里,我们就要先来说说服务器的分类了,一般来说,linux服务器可以分为2种类型,一种是CPU密集型,一种是IO密集型,
CPU密集的意思是该任务需要大量的运算,而没有阻塞,CPU一直全速运行
CPU密集任务只有在真正多核CPU上才可能得到加速(通过多线程)
而在单核CPU上,无论你开几个模拟的多线程该任务都不可能得到加速,
因为CPU总的运算能力就那些CPU密集型任务配置尽可能少的线程数量:
A:由于IO密集型任务线程并不是一直在执行任务,
则应配置经可能多的线程,如CPU核数 * 2
B:IO密集型,即该任务需要大量的IO,即大量的阻塞。
在单线程上运行IO密集型的任务会导致浪费大量的 CPU运算能力浪费在等待。
所以在IO密集型任务中使用多线程可以大大的加速程序运行,即使在单核CPU上,这种加速主要就是利用了被浪费掉的阻塞时间。
IO密集型时,大部分线程都阻塞,故需要多配置线程数:
了解了这两种类型之后,我们现在就写一个demo类来探究线程池的使用原理,经过验证,最佳线程池使用原理如下demo所述,大家可以结合
这个demo自己去生产上面合理的设置线程池数量大小,下面的这个demo绝对是经得起生产环境考验的,具体以自己的业务背景为主,
package com.mooc.house.user.common;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @ClassName 根据CPU核数合理设置线程池大小,测试模拟探究
* @Description DOTO
* @Author mischen
* @Date 2021/3/21 8:02
* @Version 1.0
**/
public class Demo3 {
//最大可用的CPU核数
public static final int PROCESSORS = Runtime.getRuntime().availableProcessors();
//线程最大的空闲存活时间,单位为秒
public static final int KEEPALIVETIME = 60;
//任务缓存队列长度
public static final int BLOCKINGQUEUE_LENGTH = 500;
/**这里如果设置无界队列,高并发情况下有可能会出现内存飙升,所以队列这里引入有界队列,使用
*LinkedBlockingQueue是因为这个队列效率高,按照FIFO优先级来处理,先放入队列的优先处理,但是这里就需要配置一个
* 拒绝策略,指定拒绝策略的CallerRunsPolicy
* 该策略既不会抛弃任务也不会抛出异常,而是在调用execute()的线程中运行任务。比如我们在主线程中调用了execute(task)方法
* 但是这时workQueue已经满了,并且也不会创建的新的线程了。这时候将会在主线程中直接运行execute中的task。
**/
public ThreadPoolExecutor createThreadPool() {
return new ThreadPoolExecutor(PROCESSORS * 2, PROCESSORS * 4, KEEPALIVETIME, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(10),new ThreadPoolExecutor.CallerRunsPolicy());
}
public synchronized static void main(String[] args) {
System.out.println(Demo3.PROCESSORS);
new Demo3().test();
}
public synchronized void test(){
ThreadPoolExecutor threadPoolExecutor=new Demo3().createThreadPool();
for (int i = 0; i <= 100; i++) {
MyTask myTask = new MyTask(i);
System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
System.out.println("当前线程池等待的数量为:" + threadPoolExecutor.getQueue().size());
threadPoolExecutor.execute(myTask);
}
threadPoolExecutor.shutdown();
}
}
class MyTask implements Runnable{
private int i;
public MyTask(int i){
this.i=i;
}
@Override
public void run() {
System.out.println("任务"+i+"开始执行"+System.currentTimeMillis());
for (int i=0;i<32766;i++){
Random random=new Random();
int randNum=random.nextInt();
int[] a={1,2,3,4,5,6,9,18,290,238,991,100,19,1932,randNum};
Arrays.sort(a);
Arrays.hashCode(a);
Arrays.stream(a);
}
System.out.println("任务"+i+"结束执行"+System.currentTimeMillis());
}
}