计算机系统应用教程网站

网站首页 > 技术文章 正文

创建线程池的几个参数,你理解了吗

btikc 2024-10-22 10:31:04 技术文章 4 ℃ 0 评论

最近忙着整理一个“屎山”项目,2017年的项目,也不算老,上篇文章多线程OOM也是这个“屎山”项目的一角。今天我们来讲上篇文章提到的创建线程池的7个参数,说到这里,有的小伙伴就会问了,“为什么是7个参数呢?我创建线程池不需要7个参数呀。”

进入正题,且听我细细道来。

JDK为了降低我们使用线程池的门槛,封装了一些创建线程池的方法。

Executors类里面封装的创建线程池方法

如:Executors.newFixedThreadPoolExecutors.newSingleThreadExecutorExecutors.newCachedThreadPool,由于把门槛降得太低,我们就掉以轻心了,不会过多的查看底层的实现,直接按照参数提示填入参数,然后可怕的事情就发生了。

一起来看看这些方法的底层实现吧~

newFixedThreadPool的实现

newSingleThreadExecutor的实现

newCachedThreadPool的实现

看了上面的底层实现以后,我们知道其实底层最后都是调用ThreadPoolExecutor来创建线程池。

打开ThreadPoolExecutor类,找到其构造方法:

ThreadPoolExecutor构造方法

数一数,参数最多的构造方法,是7个吧,这就回答文章开头那位小伙伴的疑问了。

这里我们也可以稍微总结性的说:由于JDK封装的快速方法都是通过ThreadPoolExecutor来创建线程池,所以我们只需要把ThreadPoolExecutor7个构造参数理解了,也就基本上知道怎么创建线程池了。

7个构造参数的方法

corePoolSize:核心线程数

maximumPoolSize:最高峰线程数量,包含核心线程数

keepAliveTime:最高峰线程的存活时间

unit:存活时间的单位

workQueue:等候区队列

threadFactory:线程创建工厂

handler:拒绝策略

看了参数懵的没事,大概有个印象就行。

这里拿具体银行办理业务的场景来描述这些参数,假设有此场景:

午休时间去银行办理业务,银行有4个窗口,由于是午休的时间,当前只打开了2个窗口办理业务,客户取号后,在候客区等着叫号办理业务。由于天气好,来银行办理业务的客户特别多,把银行的候客区也塞得满满当当的,这个时候银行就在门口竖立起一块牌子:“今日暂停办理业务。”

银行办理业务流程图

结合流程图来描述,银行有9个客户来办理业务,当值窗口有2个,未开窗口有2个,候客区座位有5个。

当值窗口理解为我们的核心线程数(corePoolSize),当办理业务高峰期来临的时候,打开之前的未开窗口,这个时期办理业务的窗口为当值窗口 + 未开窗口,即最高峰线程数量(maximumPoolSize);如果这个时候继续有顾客进来,会进入候客区,即等候区队列(workQueue),假如这个时候有第10个客户来办理业务,当值窗口,未开窗口,候客区都已经满了的时候,就会暂停办理业务,即拒绝策略(handler);其中我们没有说明的最高峰线程的存活时间存活时间的单位线程创建工厂这三个参数。线程创建工厂根据字面意思直接理解就是创建线程的对象,而最高峰线程的存活时间(keepAliveTime)存活时间的单位(unit)就是在业务处理完毕以后,来临时支援服务的窗口等待多久进行窗口释放,回归到核心线程数的数量。

没有理解也没有关系,继续通过代码来理解。

取钱函数

// 取钱函数
public static void withdraw() {
  try {
    // 取钱需要20秒
    System.out.println(Thread.currentThread().getName() + "正在取钱业务 ...");
    Thread.sleep(20000);
    System.out.println(Thread.currentThread().getName() + "取钱业务完成");
  } catch (InterruptedException e) {
    throw new RuntimeException(e);
  }
}

具体执行

// 申明参数
int corePoolSize = 2;
int maximumPoolSize = 4;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(5);
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
// 创建
ExecutorService threadPool = new ThreadPoolExecutor(corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        unit,
        workQueue,
        threadFactory,
        handler
);

// 执行具体的业务
try {
    for (int i = 1; i <= 9; i++) {
        threadPool.execute(t::withdraw);
    }
} catch (Exception exception) {
    exception.printStackTrace();
} finally {
    threadPool.shutdown();
}

修改等待队列

多线程的7个参数理解了吗?没有理解的,对照银行业务流程图和代码多看几遍,应该就能理解了。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表