关于如何合理设置线程池参数解决方案

简介: 关于如何合理设置线程池参数解决方案(ThreadPoolExecutor)

# 关于如何合理设置线程池参数解决方案(ThreadPoolExecutor)

## 线程池参数有哪些

我们直接来看构造方法



```java

...

public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6,

  ThreadFactory var7, RejectedExecutionHandler var8) {

 this.ctl = new AtomicInteger(ctlOf(-536870912, 0));

 this.mainLock = new ReentrantLock();

 this.workers = new HashSet();

 this.termination = this.mainLock.newCondition();

 if (var1 >= 0 && var2 > 0 && var2 >= var1 && var3 >= 0L) {

  if (var6 != null && var7 != null && var8 != null) {

   this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();

   //核心线程数

   this.corePoolSize = var1;

   //最大线程数

   this.maximumPoolSize = var2;

   //工作队列

   this.workQueue = var6;

   //线程存活时间

   this.keepAliveTime = var5.toNanos(var3);

   //线程工厂

   this.threadFactory = var7;

   //拒绝策略

   this.handler = var8;

  } else {

   throw new NullPointerException();

  }

 } else {

  throw new IllegalArgumentException();

 }

}

...

```

根据构造方法我们可以观察有7个参数

最最重要的三个参数,该解决方案也是围绕着这三个参数进行展开。

**corePoolSize**

**maximumPoolSize**

**workQueue**




## 美T是这么做的

大家想一想,美T饭点时的业务峰值和凌晨的业务峰值一样吗?这就要求在高峰期的时候,处理业务的线程能覆盖住业务量(当然nginx负载均衡、或其它限流框架也能做到这点,这里仅讨论在一个服务内如何做到伸缩自如),所以根据业务峰去做出调整即为合理的解决方案。


### 线程池处理任务流程

image.png

根据上面的流程图,我们只需要在三个关键点去做到动态配置即可,下面一一列举


## 动态设置corePoolSize

ThreadPoolExecutor里面给我们提供了setCorePoolSize(int var1)方法,能让我们在线程池运行的过程中去动态设置核心线程数。

### 源码解析


```java

public void setCorePoolSize(int var1) {

 if (var1 < 0) {

  throw new IllegalArgumentException();

 } else {

  int var2 = var1 - this.corePoolSize;

  this.corePoolSize = var1;

  if (workerCountOf(this.ctl.get()) > var1) {

   this.interruptIdleWorkers();

  } else if (var2 > 0) {

   int var3 = Math.min(var2, this.workQueue.size());


   while (var3-- > 0 && this.addWorker((Runnable) null, true) && !this.workQueue.isEmpty()) {

    ;

   }

  }


 }

}

```

步骤:

1.首先判断传进来的var1是否符合要求、不符合直接抛出异常。


2.将corePoolSize 设置为var1。


3.workerCountOf(this.ctl.get())这个方法就是判断当前线程池正在工作的线程数,判断是否大于var1(ctl这个属性通过高位、低位来维护了线程数量,还维护了线程池的运行状态,为什么这么使用,因为在线程池的大多数方法中都需要去获取线程池工作线程的数量以及状态,AtomicInteger ctl本身是一个线程安全的对象),如果大于var1,则像正在工作的线程发出中断请求,以回收线程。


4.如果小于var1,会将var2(var1与旧corePoolSize 的差值)会跟现在阻塞队列的长度进行比较,获取比较小的那个值var3,取出阻塞队列var3个任务执行。


5.这样就完成了对一个正在运行的线程池动态改变corePoolSize 的操作。


## 动态设置maximumPoolSize

ThreadPoolExecutor里面给我们提供了setMaximumPoolSize(int var1)方法,能让我们在线程池运行的过程中去动态设置最大线程数。


```java

public void setMaximumPoolSize(int var1) {

 if (var1 > 0 && var1 >= this.corePoolSize) {

  this.maximumPoolSize = var1;

  if (workerCountOf(this.ctl.get()) > var1) {

   this.interruptIdleWorkers();

  }


 } else {

  throw new IllegalArgumentException();

 }

}

```


这个相对操作核心线程来说就比较简单了


步骤:

1.当然还是先判断传入的参数符不符合规范,不符合直接抛出异常


2.将maximumPoolSize 设置为var1


3.判断当前工作线程数是否大于var1,大于则向当前工作线程发出中断请求,回收线程


## 重写workQueue

因为阻塞队列中的**capacity**也就是初始化队列的长度使用==final==字符来进行修饰,所以当队列长度一旦确定就不可更改

美团技术团队的解决方法是将**LinkedBlockingQueue**重写了,也就是把**capacity**的==final==去掉,达到了通过改变**capacity**的值来达到控制阻塞队列长度的目的


创作不易,转载请标注!!!

目录
相关文章
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
2月前
|
监控 Java
线程池大小如何设置
在并发编程中,线程池是一个非常重要的组件,它不仅能够提高程序的响应速度,还能有效地利用系统资源。合理设置线程池的大小对于优化系统性能至关重要。本文将探讨如何根据应用场景和系统资源来设置线程池的大小。
|
2月前
|
Java
线程池七大参数
核心线程数:线程池中的基本线程数量 最大线程数:当阻塞队列满了之后,逐一启动 最大线程的存活时间:当阻塞队列的任务执行完后,最大线长的回收时间 最大线程的存活时间单位 阻塞队列:当核心线程满后,后面来的任务都进入阻塞队列 线程工厂:用于生产线程
|
2月前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
6月前
|
SQL druid Java
线程池相关故障问题之Druid数据库连接池中,为何需要设置TransactionTimeout
线程池相关故障问题之Druid数据库连接池中,为何需要设置TransactionTimeout
188 0
|
4月前
|
Java Spring
spring多线程实现+合理设置最大线程数和核心线程数
本文介绍了手动设置线程池时的最大线程数和核心线程数配置方法,建议根据CPU核数及程序类型(CPU密集型或IO密集型)来合理设定。对于IO密集型,核心线程数设为CPU核数的两倍;CPU密集型则设为CPU核数加一。此外,还讨论了`maxPoolSize`、`keepAliveTime`、`allowCoreThreadTimeout`和`queueCapacity`等参数的设置策略,以确保线程池高效稳定运行。
455 10
spring多线程实现+合理设置最大线程数和核心线程数
|
3月前
|
Java
线程池设置原则
线程池设置原则
|
3月前
|
JavaScript 前端开发 安全
轻松上手Web Worker:多线程解决方案的使用方法与实战指南
轻松上手Web Worker:多线程解决方案的使用方法与实战指南
76 0
|
5月前
|
缓存 Java
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
这篇文章详细介绍了Java中线程的四种初始化方式,包括继承Thread类、实现Runnable接口、实现Callable接口与FutureTask结合使用,以及使用线程池。同时,还深入探讨了线程池的七大参数及其作用,解释了线程池的运行流程,并列举了四种常见的线程池类型。最后,阐述了在开发中使用线程池的原因,如降低资源消耗、提高响应速度和增强线程的可管理性。
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
|
3月前
|
设计模式 Java 物联网
【多线程-从零开始-玖】内核态,用户态,线程池的参数、使用方法详解
【多线程-从零开始-玖】内核态,用户态,线程池的参数、使用方法详解
76 0