springmvc-servlet.xml配置文件
<!-- Spring线程池 -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 最小xianc-->
<property name="corePoolSize" value="3" />
<!-- 最大线程数 -->
<property name="maxPoolSize" value="10" />
<!-- 队列最大长度 >=mainExecutor.maxSize -->
<property name="queueCapacity" value="25" />
<!-- 线程池维护线程所允许的空闲时间 -->
<property name="keepAliveSeconds" value="3000" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. -->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
属性字段说明:
corePoolSize: 线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:再刚刚创建ThreadPoolExecutor的时候。线程不会立刻启动,而是要等到有任务提交时才会启动,除非调用方法事先启动核心线程。所以,没有任务需要执行的时候,线程池的大小不一定是corePoolSize;
maxPoolSize: 线程池中允许的最大线程数,线程池中的当前线程数不会超过该值。如果队列中的任务已满,并且当前线程数小于maxPoolSize,就会创建新的线程来执行任务。
提交任务:
1.无返回值的任务使用execute(Runnable)
2.有返回值得任务使用submit(Runnable)
新提交一个任务时的处理流程:
1.如果线程池的当前大小没有达到核心线程池数量(poolSize < corePoolSize),那么就新建一个线程处理新提交的任务;
2.如果当前大小已经达到核心线程池数量。就将新提交的任务提交到阻塞队列排队。等候处理workQueue.offer(command);
3.如果队列容量已经达到上限,并且当前大小poolSize没有达到maxPoolSize,那么就新增线程来处理任务;
4.如果队列已满,并且当前线程数量已经达到上限,那么意味着线程池的处理能力已经达到了极限,此时需要拒绝新增加的任务。至于如何拒绝处理新增的任务,取决于线程池的饱和策略RejectedExecutionHandler。
rejectedExecutionHandler 字段用于配置拒绝策略,常用的拒绝策略如下:
一、AbortPolicy
二、DiscardPolicy
三、DiscardOldestPolicy
四、CallerRunsPolicy
五、自定义
第一种:AbortPolicy
该策略是线程池的默认策略。使用该策略时,如果线程池和队列都满了,新的任务会被丢弃并且抛出RejectedExecutionException异常;
源码:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//不做任何处理,直接抛出异常
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
第二种:DiscardPolicy
这个策略,如果线程池和队列都满了,新的任务会被丢弃并且不会产生异常;
源码:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//就是一个空的方法
}
第三种:DiscardOldestPolicy
这个策略从字面上理解,对其最老的。即如果线程池和队列都满了,会将最早进入队列的任务删掉腾出空间,再加入队列。由于队列是队尾进,队头出,所以队头元素是最老的,因此每次都是移除队头元素后再尝试入队。
源码:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//移除队头元素
e.getQueue().poll();
//再尝试入队
e.execute(r);
}
}
第四种:CallerRunsPolicy
使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行。就像是个急脾气的人,等不来别人干,干脆自己干。
源码:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//直接执行run方法
r.run();
}
}
第五种:自定义
如果以上策略都不符合业务场景,那么可以自己定义一个拒绝策略,只要实现RejectedExecutionHandler接口。
例如:
public class MyRejectPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//Sender是我的Runnable类,里面有message字段
if (r instanceof Sender) {
Sender sender = (Sender) r;
//直接打印
System.out.println(sender.getMessage());
}
}
}
以上5种策略没有好坏之分,只是使用不同的场景,具体哪种适合得根据具体场景和业务来做选择
以下博客提供帮助:
https://blog.youkuaiyun.com/jgteng/article/details/54411423
https://blog.youkuaiyun.com/foreverling/article/details/78073105

被折叠的 条评论
为什么被折叠?



