Spring ThreadPoolTask​​Executor只运行一个线程

问题描述:

我们在我们的JMS使用者中使用ThreadPoolExecutor并将它注入到DefaultMessageListenerContainer中。我期望这是为许多消息运行并发线程,但是我们的日志显示线程ID不会改变。我们的日志记录显示,对于不同的消息处理,线程ID在24处始终相同。Spring ThreadPoolTask​​Executor只运行一个线程

这是在该方案中的弹簧配置:

<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer"  
     p:connectionFactory-ref="cachedConnectionFactory" 
     p:destination-ref="formsCRRDestination" 
     p:messageListener-ref="formServicePojo" 
     p:concurrentConsumers="5" 
     p:idleTaskExecutionLimit="1" 
     p:maxConcurrentConsumers="25" 
     p:taskExecutor-ref="threadPoolExecutor"   
     destroy-method="doShutdown"  
    > 


<bean id="threadPoolExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" > 
     <property name="corePoolSize" value="1"/> 
     <property name="maxPoolSize" value="15"/> 
     <property name="keepAliveSeconds" value="30"/> 
    </bean> 

不注入threadPoolExectuor豆成使用DefaultMessageListenerContainer后,消息现在被在不同的线程中执行。

这是生成的配置:

<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer"  
      p:connectionFactory-ref="cachedConnectionFactory" 
      p:destination-ref="formsCRRDestination" 
      p:messageListener-ref="formServicePojo" 
      p:concurrentConsumers="5" 
      p:idleTaskExecutionLimit="1" 
      p:maxConcurrentConsumers="25"  
      destroy-method="doShutdown"  
     > 

我曾尝试阅读文档,我不明白为什么会这样。任何解释?

+0

我没有进入jms,但是您是否尝试同时发送很多消息?我猜这里的机制是只根据需求启动一个新线程(即没有空闲线程和新消息)。 – 2010-11-24 17:21:53

+0

是的,我确实尝试在同一时间发送很多消息,只有一些消息需要很长时间才能处理。 – Jeune 2010-11-24 17:24:25

通过ThreadPoolTaskExecutor code in Spring去和阅读Java文档为ThreadPoolTaskExecutor后,我觉得这就是答案:

无界队列。使用无限制的队列(例如 LinkedBlockingQueue不带 预定义容量)将导致新的 任务在所有 corePoolSize线程繁忙的情况下排队。因此, 不会超过corePoolSize线程 永远被创建。 (和 maximumPoolSize的值,因此不具有 任何影响。)

在我们的配置上面,我们正在使用的LinkedBlockingQueue默认情况下,我们的corePoolSize为1。这就是为什么maximumPoolSize不会有什么影响。

+1

考虑编辑您的答案以添加有关如何解决问题的信息。什么java代码或弹簧配置应该改变?谢谢。 – Gray 2017-02-23 16:44:10

将corePoolSize更改为10,那么您将获得10个线程同时运行。 阅读java.util.concurrent.ThreadPoolExecutor中这是春天ThreadPoolTask​​Executor类的骨干javadoc,那么你将有更好地了解如何配置的corePoolSize和maxPoolSize和queueCapacity

我想选择的答案是错误的。 IIRC,顺便ThreadPoolTaskExecutor(最终的ThreadPoolExecutor在JDK)工作是

  1. ThreadPoolTask​​Executor类创建线程最多corePoolSize时,它的启动。
  2. 它将请求提交至corePoolSize并让线程处理任务。
  3. 如果在所有线程都忙时有更多请求传入,ThreadPoolTask​​Executor会将这些请求排入内部队列。这可能会有问题,因为如果不指定队列queueCapacity,则此队列大小将为Integer.MAX_VALUE作为默认值。
  4. 在#3中添加的请求将在线程池中存在任何可用线程时由线程执行。
  5. 如果请求继续来临,并且所有线程都忙&队列已满,ThreadPoolTask​​Executor开始创建新线程,直到maxPoolSize处理请求。
  6. 如果对这些请求(增加的线程数+队列大小),那么任务将被拒绝或遵循您指定的策略。

所以在这里我想问题是,无论是1)你的消费者是不够快或2)你是堆叠请求太慢,所以你corePoolSize指定一个线程足以处理新传入的请求+排队任务,而不允许ThreadPoolTask​​Executor创建新线程。我敢肯定,如果你更加努力地推动它,或者将队列的容量设置为较小的数量(如5〜10),您将能够看到线程数量正在增加。

试试这个:

<bean id="threadPoolTaskExecutor" 
     class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
     <property name="corePoolSize" value="10" /> 
     <property name="maxPoolSize" value="25" /> 
     <property name="queueCapacity" value="30" /> 
</bean> 
  • 这将在初始化时创建10个线程。
  • 如果所有10个线程都处于忙碌状态并且出现新任务,那么它会将任务保留在队列中。
  • 如果队列已满,它将创建第11个线程并且将一直持续到25.
  • 然后会抛出TaskRejected异常。