Spring 线程池

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

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值