ThreadPoolExecutor线程池及线程扩展策略

本文介绍了Java中的ThreadPoolExecutor线程池的构造方法及其参数,包括核心线程数、最大线程数、存活时间等,并展示了如何创建不同类型的线程池,如固定线程池、缓存线程池和单线程池。此外,还讨论了自定义线程工厂和拒绝策略的实现方式,通过CustomThreadPoolExecutor类进行实例演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述  
1、ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务; 
2、Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。 
3、先来了解其线程池管理的机制,有助于正确使用,避免错误使用导致严重故障。同时可以根据自己的需求实现自己的线程池
 

二、核心构造方法讲解  
下面是ThreadPoolExecutor最核心的构造方法  
Java代码   收藏代码
  1. public ThreadPoolExecutor(int corePoolSize,  
  2.                               int maximumPoolSize,  
  3.                               long keepAliveTime,  
  4.                               TimeUnit unit,  
  5.                               BlockingQueue<Runnable> workQueue,  
  6.                               ThreadFactory threadFactory,  
  7.                               RejectedExecutionHandler handler) {  
  8.         if (corePoolSize < 0 ||  
  9.             maximumPoolSize <= 0 ||  
  10.             maximumPoolSize < corePoolSize ||  
  11.             keepAliveTime < 0)  
  12.             throw new IllegalArgumentException();  
  13.         if (workQueue == null || threadFactory == null || handler == null)  
  14.             throw new NullPointerException();  
  15.         this.corePoolSize = corePoolSize;  
  16.         this.maximumPoolSize = maximumPoolSize;  
  17.         this.workQueue = workQueue;  
  18.         this.keepAliveTime = unit.toNanos(keepAliveTime);  
  19.         this.threadFactory = threadFactory;  
  20.         this.handler = handler;  
  21.     }  

构造方法参数讲解  
参数名 作用
corePoolSize 核心线程池大小
maximumPoolSize 最大线程池大小
keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
TimeUnit keepAliveTime时间单位
workQueue 阻塞任务队列
threadFactory 新建线程工厂
RejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理


重点讲解:  
其中比较容易让人误解的是:corePoolSize,maximumPoolSize,workQueue之间关系。 

1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。 
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务 
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理 
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程 
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
 

线程管理机制图示:  


三、Executors提供的线程池配置方案  

1、构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理  
Java代码   收藏代码
  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2.         return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                       0L, TimeUnit.MILLISECONDS,  
  4.                                       new LinkedBlockingQueue<Runnable>());  
  5.     }  

2、构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁  
Java代码   收藏代码
  1. public static ExecutorService newCachedThreadPool() {  
  2.         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  
  3.                                       60L, TimeUnit.SECONDS,  
  4.                                       new SynchronousQueue<Runnable>());  
  5.     }  

3、构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行  
Java代码   收藏代码
  1. public static ExecutorService newSingleThreadExecutor() {  
  2.         return new FinalizableDelegatedExecutorService  
  3.             (new ThreadPoolExecutor(11,  
  4.                                     0L, TimeUnit.MILLISECONDS,  
  5.                                     new LinkedBlockingQueue<Runnable>()));  
  6.     }  

4、构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由于DelayedWorkQueue是无界队列,所以这个值是没有意义的  
Java代码   收藏代码
  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {  
  2.         return new ScheduledThreadPoolExecutor(corePoolSize);  
  3.     }  
  4.   
<think>好的,我现在需要回答用户关于ThreadPoolExecutor线程池提交任务的方式及其区别的问题,特别是execute和submit方法的使用场景和特点。首先,我需要回顾一下用户提供的引用内容,确保回答准确并符合参考资料。 首先,根据引用[1]、[3]、[4]、[5],execute方法用于提交不需要返回值的任务,参数是Runnable,且无法判断任务是否行成功。而submit方法则可以提交Callable或Runnable任务,并返回Future对象,用于获取任务结果或判断状态。引用[2]提到submit方法在ForkJoinPool中的使用,但这里主要关注ThreadPoolExecutor。引用[5]明确指出submit返回Future,可以判断任务是否完成,而execute没有返回值。 接下来,我需要组织这些信息,分点说明两种方法的区别,包括参数类型、返回值、异常处理和使用场景。需要确保语言清晰,结构合理。同时,用户要求使用中文,注意术语的准确翻译,比如“Future”、“Callable”等可能需要保留英文,但解释时要清楚。 可能还需要补充一些细节,比如submit如何处理Callable和Runnable的不同,以及execute在任务失败时的异常处理方式。例如,当使用execute时,未被捕获的异常会导致线程终止,而submit可以通过Future.get()捕获异常。 另外,用户示例中的代码部分需要按照要求使用正确的格式,比如代码块用反引号包裹,并注明语言类型。同时,数学表达式要使用$...$,但在这个问题中可能涉及较少,但如果有性能分析中的公式,比如时间复杂度,需要正确应用。 最后,生成相关问题,需要围绕线程池的任务提交方式扩展,比如异常处理区别、如何选择方法、Future的用法等。确保问题相关且有深度。 现在,我需要将这些思考整合成一个结构化的回答,确保每个部分都有引用支持,并且自然插入引用标识。同时,保持回答的易懂性和实用性,帮助用户真正理解两者的区别和应用场景。</think>### ThreadPoolExecutor任务提交方式解析 ThreadPoolExecutor 线程池主要通过 $execute()$ 和 $submit()$ 两种方法提交任务,其核心区别体现在 **任务类型**、**返回值** 和 **异常处理** 三个方面。 --- #### 一、execute() 方法特性 1. **任务类型限制** 仅支持提交实现 `Runnable` 接口的任务,不接受 `Callable` 类型任务[^4][^5]。 ```java // 典型用法示例 executor.execute(new Runnable() { @Override public void run() { System.out.println("Task executed via execute()"); } }); ``` 2. **无返回值** 方法定义为 `void execute(Runnable command)`,无法直接获取任务行结果[^1][^3]。若任务行过程中抛出未捕获异常,可能导致线程终止且异常信息丢失[^5]。 3. **适用场景** 适用于 **不需要关注行结果或异常** 的异步任务(如日志记录、非关键计算)[^1][^5]。 --- #### 二、submit() 方法特性 1. **任务类型灵活** 支持提交 `Runnable` 和 `Callable` 两种任务类型[^5]。提交 `Callable` 时可生成返回值,提交 `Runnable` 时默认返回 `null`[^5]。 ```java // 提交Callable任务 Future<Integer> future = executor.submit(() -> { return 42; // 返回计算结果 }); ``` 2. **返回Future对象** 通过 `Future<T>` 可 **异步获取任务结果** 或 **捕获异常**。例如: ```java try { Integer result = future.get(); // 阻塞获取结果 } catch (ExecutionException e) { Throwable cause = e.getCause(); // 获取任务中的原始异常 } ``` 3. **异常处理机制** 任务中的异常会被封装到 `Future` 中,调用 `Future.get()` 时会抛出 `ExecutionException`,避免线程因未处理异常而终止[^5]。 4. **适用场景** 需 **监控任务状态**、**获取计算结果** 或 **集中处理异常** 的场景(如批量数据处理、分布式任务协调)[^5][^2]。 --- #### 三、关键差异对比 | 特性 | execute() | submit() | |---------------------|-----------------------------------------|----------------------------------------| | **任务类型** | 仅 `Runnable` | `Runnable` 或 `Callable` | | **返回值** | 无 | `Future<T>` 对象 | | **异常处理** | 直接抛出,可能导致线程终止 | 异常封装到 `Future`,需显式调用 `get()` 捕获 | | **结果获取** | 不支持 | 通过 `Future.get()` 异步获取 | --- #### 四、选择策略 - **优先使用 submit()** 当需要 **任务状态跟踪** 或 **结果依赖** 时(如任务链式行),`submit()` 配合 `Future` 更灵活[^2]。 - **简单任务使用 execute()** 若任务逻辑简单且无需结果反馈(如触发式事件),`execute()` 代码更简洁[^1][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值