/**
* 参数介绍:
* corePoolSize 核心线程数,指保留的线程池大小(不超过maximumPoolSize值时,线程池中最多有corePoolSize 个线程工作)。
* maximumPoolSize 指的是线程池的最大大小(线程池中最大有corePoolSize 个线程可运行)
* keepAliveTime 指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。
* unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS,
* MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。
* workQueue 表示存放任务的队列(存放需要被线程池执行的线程队列)。
* threadFactory - 执行程序创建新线程时使用的工厂。
* handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
*/
@Configuration
public class CustomThreadFactory {
private int corePoolSize = 3;
private int maximumPoolSize = 10;
private long keepAliveTime = 0;
/**
* 1、直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。
* 在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,
* 因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。
* 直接提交通常要求无界 maximumPoolSizes, 以避免拒绝新提交的任务。
* 当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
**/
@Bean("getSynchronousQueueExecutorService")
public ExecutorService getSynchronousQueueExecutorService() {
ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder().namingPattern("syn-pool-%d").daemon(true).build();
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.MILLISECONDS,
new SynchronousQueue(), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
}
/**
* 2、无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。
* 这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;
* 例如,在 Web页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性
*/
@Bean("getLinkedBlockingQueueExecutorService")
public ExecutorService getLinkedBlockingQueueExecutorService() {
ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder().namingPattern("link-pool-%d").daemon(true).build();
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(), namedThreadFactory);
}
/**
* 3、有界队列。当使用有限的 maximumPoolSizes时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。
* 队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开 销,但是可能导致人工降低吞吐量。
* 如果任务频繁阻塞(例如,如果它们是 I/O边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
*线程策略默认提供4种策略
* RejectedExecutionHandler:无法处理线程的handler
* RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机会。在ThreadPoolExecutor中已经默认包含了4中策略源代码如下
* CallerRunsPolicy(直接运行run方法):线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
* 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
* 2. if (!e.isShutdown()) {
* 3. r.run();
* 4. }
* 5. }
* 这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用线程本身run方法来执行。
* AbortPolicy(抛异常):处理程序遭到拒绝将抛出运行时RejectedExecutionException
* 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
* 2. throw new RejectedExecutionException();
* 3. }
* 这种策略直接抛出异常,丢弃任务。
* DiscardPolicy(直接丢弃):不能执行的任务将被删除
* 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
* 2. }
* 这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。
* DiscardOldestPolicy(抛弃最老的线程):如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后
* 重试执行程序(如果再次失败,则重复此过程)
* 1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
* 2. if (!e.isShutdown()) {
* 3. e.getQueue().poll();
* 4. e.execute(r);
* 5. }
* }
* 该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。这个策略需要适当小心。
*/
@Bean("getArrayBlockingQueueExecutorService")
public ExecutorService getArrayBlockingQueueExecutorService() {
ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder().namingPattern("array-pool-%d").daemon(true).build();
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue(100), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
}