整个ThreadPoolExecutor的任务处理有4步操作:
- 第一步,初始的poolSize < corePoolSize,提交的runnable任务,会直接做为new一个Thread的参数,立马执行
- 第二步,当提交的任务数超过了corePoolSize,就进入了第二步操作。会将当前的runable提交到一个block queue中
- 第三步,如果block queue是个有界队列,当队列满了之后就进入了第三步。如果poolSize < maximumPoolsize时,会尝试new 一个Thread的进行救急处理,立马执行对应的runnable任务
- 第四步,如果第三步救急方案也无法处理了,就会走到第四步执行reject操作。
几点说明:(相信这些网上一搜一大把,我这里简单介绍下,为后面做一下铺垫)
- block queue有以下几种实现:
1. ArrayBlockingQueue : 有界的数组队列
2. LinkedBlockingQueue : 可支持有界/无界的队列,使用链表实现
3. PriorityBlockingQueue : 优先队列,可以针对任务排序
4. SynchronousQueue : 队列长度为1的队列,和Array有点区别就是:client thread提交到block queue会是一个阻塞过程,直到有一个worker thread连接上来poll task。 - RejectExecutionHandler是针对任务无法处理时的一些自保护处理:
-
容易被人忽略的点:1. pool threads启动后,以后的任务获取都会通过block queue中,获取堆积的runnable task.所以建议: block size >= corePoolSize ,不然线程池就没任何意义2. corePoolSize 和 maximumPoolSize的区别, 和大家正常理解的数据库连接池不太一样。* 据dbcp pool为例,会有minIdle , maxActive配置。minIdle代表是常驻内存中的threads数量,maxActive代表是工作的最大线程数。* 这里的corePoolSize就是连接池的maxActive的概念,它没有minIdle的概念(每个线程可以设置keepAliveTime,超 过多少时间多有任务后销毁线程,默认只会针对maximumPoolSize参数的线程生效,可以设置 allowCoreThreadTimeOut=true,就可以对corePoolSize进行idle回收)。* 这里的maximumPoolSize,是一种救急措施的第一层。当threadPoolExecutor的工作threads存在满负荷,并且 block queue队列也满了,这时代表接近崩溃边缘。这时允许临时起一批threads,用来处理runnable,处理完后通过keepAliveTime进 行调度回收。所以建议: maximumPoolSize >= corePoolSize =期望的最大线程数。 (我曾经配置了corePoolSize=1, maximumPoolSize=20, blockqueue为无界队列,最后就成了单线程工作的pool。典型的配置错误)3. 善用blockqueue和reject组合. 这里要重点推荐下CallsRun的Rejected Handler,从字面意思就是让调用者自己来运行。我们经常会在线上使用一些线程池做异步处理,比如我前面做的(业务层)异步并行加载技术分析和设计, 将 原本串行的请求都变为了并行操作,但过多的并行会增加系统的负载(比如软中断,上下文切换)。所以肯定需要对线程池做一个size限制。但是为了引入异步 操作后,避免因在block queue的等待时间过长,所以需要在队列满的时,执行一个callsRun的策略,并行的操作又转为一个串行处理,这样就可以保证尽量少的延迟影响。所以建议: RejectExecutionHandler = CallsRun , blockqueue size = 2 * poolSize (为啥是2倍poolSize,主要一个考虑就是瞬间高峰处理,允许一个thread等待一个runnable任务)
-
1. Reject 直接抛出Reject exception
2. Discard 直接忽略该runnable,不可取
3. DiscardOldest 丢弃最早入队列的的任务
4. CallsRun 直接让原先的client thread做为worker线程,进行执行
相关推荐
线程池ThreadPoolExecutor使用简介与方法实例 线程池ThreadPoolExecutor是Java并发编程中一个非常重要的概念,它允许开发者将任务提交给线程池,并由线程池来管理这些任务的执行。今天,我们将对线程池...
ThreadPoolExecutor线程池的使用方法 ThreadPoolExecutor线程池是Java提供的开发框架,管理线程的创建、销毁、优化、监控等。它提供了四种不同的任务队列:ArrayBlockingQueue、LinkedBlockingQueue、...
本文将详细讲解如何使用Java中的`ThreadPoolExecutor`来抓取论坛帖子列表,结合源码分析和实用工具的应用。 首先,我们要了解线程池的基本原理。线程池是由一组预先创建的线程组成的,这些线程可以复用,而不是每次...
非核心线程在没有任务执行的情况下等待新任务的最大时间。超过这个时间后,非核心线程会被终止。 - **unit**:与 `keepAliveTime` 相关联的时间单位。 - **workQueue**:用于存放等待执行的任务的阻塞队列。如果所有...
这个类是Spring对Java内置的`java.util.concurrent.ThreadPoolExecutor`的封装,允许开发者在Spring应用上下文中声明式地定义线程池。在本篇文章中,我们将深入探讨`ThreadPoolTaskExecutor`的配置及其使用,并结合`...
在使用ThreadPoolExecutor执行任务时,我们可以使用FutureTask来获取任务执行结果。FutureTask是一个实现了Runnable和Future接口的类,它可以帮助我们获取任务执行结果。例如,我们可以创建一个FutureTask对象,并将...
线程池作为 Java 并发编程中的重要组件,在实际应用中被广泛使用。其核心类 `ThreadPoolExecutor` 实现了对线程的管理、调度等功能。本文将围绕 `ThreadPoolExecutor` 的核心方法 `execute()` 进行深入解析,帮助...
ThreadPoolExecutor是Java并发编程中非常重要的一个组件,它位于`java.util.concurrent`包下,用于管理线程资源,实现线程池服务。...理解和熟练使用ThreadPoolExecutor对于编写高性能的多线程Java程序至关重要。
根据提供的文件信息,我们可以深入探讨线程池`ThreadPoolExecutor`的工作原理及其实现细节,同时也会涉及并发编程中的一些关键概念和技术。 ### 线程池`ThreadPoolExecutor`概述 `ThreadPoolExecutor`是Java中非常...
在 Java 中,线程池是使用 ThreadPoolExecutor 实现的,它提供了一个线程池管理器,可以根据需要创建、管理和销毁线程。 ThreadPoolExecutor 的构造函数参数包括 corePoolSize、maximumPoolSize、keepAliveTime、...
在Django框架中,使用`asyncio`协程和`ThreadPoolExecutor`多线程可以显著提升处理I/O密集型任务的效率。这是因为协程能够利用异步编程模型,避免不必要的阻塞,而多线程则允许同时处理多个任务。下面我们将深入探讨...
在这两种情况下,使用线程池可以帮助开发者更好地管理线程资源,提高系统的性能和可靠性。 然而,在使用java线程池时,一个常见的问题是:使用完线程池后到底要不要关闭?如果不关闭线程池,可能会导致内存泄露和...
在 Spring Boot 中使用 Java 线程池 ExecutorService 的讲解 Spring Boot 作为一个流行的 Java 框架,提供了许多便捷的功能来帮助开发者快速...通过配置线程池的核心参数,我们可以根据实际情况来调整线程池的性能。
4. **提供缓冲队列**:当请求的数量超过线程池中可用线程的数量时,线程池会将请求放入一个缓冲队列中等待执行,从而避免了立即拒绝或阻塞新任务的情况。 #### Java线程池实现 在Java中,`java.util.concurrent....
知识点1: 并发编程 - 使用ThreadPoolExecutor实现多线程下载 在上述代码中,我们使用了`concurrent.futures`模块的`ThreadPoolExecutor`类来实现多线程下载。`ThreadPoolExecutor`是一个高级别的并发编程工具,它...
线程池是一种多线程管理技术,它可以有效地控制运行的线程数量,避免过多的线程导致资源浪费,同时确保在高并发情况下系统的稳定性和响应速度。 Tomcat提供了两种线程池实现,一种是基于Apache Portable Runtime ...
在使用ThreadPoolExecutor时,需要注意可能发生的死锁情况。例如,如果一个函数调用在等待另一个函数调用的结果,而这个另一个函数调用又在等待第一个函数调用的结果,那么就会形成死锁。为了避免这种情况,应当注意...
与之相比,ForkJoinPool的一个不同之处在于,它为每个线程提供了独立的工作队列,而ThreadPoolExecutor则使用共享的工作队列。 ForkJoinPool通常适用于那些可以被递归拆分为更小部分的任务。它的典型应用场景包括...
对于大型视频或高并发下载,可能需要更复杂的策略,比如使用线程池(`concurrent.futures.ThreadPoolExecutor`)或者异步IO(`asyncio`)来更有效地管理和控制资源。此外,合并过程也可以优化,例如,可以在下载的...