2010-11-24 5 views
11

Nous utilisons ThreadPoolExecutor dans notre consommation JMS et l'injecter dans un DefaultMessageListenerContainer. Je m'attends à ce que cela fonctionne des threads simultanés pour beaucoup de messages cependant nos logs montrent que l'identification de fil ne changera pas. Notre notation montre que pour le traitement différent des messages, l'identification de fil est toujours identique à 24.Spring ThreadPoolTaskExecutor ne fonctionne que un fil

Ceci est la configuration du ressort dans ce scénario:

<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> 

Après ne pas injecter le haricot threadPoolExectuor dans le DefaultMessageListenerContainer, les messages sont maintenant en cours d'exécution dans différents threads.

C'est la configuration résultante:

<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"  
     > 

J'ai essayé de lire la documentation et je ne comprends pas pourquoi cela se passe. Toute explication?

+0

Je ne suis pas dans jms, mais avez-vous essayé d'envoyer plusieurs messages en même temps? Je suppose que le mécanisme ici est de démarrer un nouveau thread uniquement à la demande (c'est-à-dire qu'il n'y a pas de thread inactif et un nouveau message arrive). –

+0

Oui, j'ai essayé d'envoyer plusieurs messages en même temps, seuls quelques messages sont longs à traiter. – Jeune

Répondre

14

Après avoir traversé la ThreadPoolTaskExecutor code in Spring et la lecture de la documentation Java pour ThreadPoolTaskExecutor Je pense que c'est la réponse:

files d'attente Unbounded. En utilisant une file d'attente sans bornes (par exemple un LinkedBlockingQueue sans capacité prédéfinie) entraînera de nouvelles tâches mises en attente dans les cas où tous les fils de corePoolSize sont occupés. Ainsi, pas plus que les threads corePoolSize jamais créés. (Et la valeur du maximumPoolSize n'a donc pas aucun effet.)

Dans notre configuration ci-dessus, nous utilisions le LinkedBlockingQueue par défaut et notre corePoolSize est 1. C'est pourquoi le maximumPoolSize ne sera pas avoir un effet.

+1

Envisagez de modifier votre réponse pour ajouter des informations sur la façon de résoudre le problème. Quel code java ou configs de printemps devrait être changé? Merci. – Gray

2

changer la corePoolSize à 10, alors vous obtiendrez 10 threads exécuter simultanément. Lire la javadoc sur java.util.concurrent.ThreadPoolExecutor qui est l'épine dorsale du ThreadPoolTaskExecutor de printemps, alors vous aurez mieux comprendre comment config le corePoolSize et MaxPoolSize et queueCapacity

7

Je pense que choisi réponse est fausse. IIRC, la manière ThreadPoolTaskExecutor (éventuellement ThreadPoolExecutor dans le JDK) de travail est

  1. ThreadPoolTaskExecutor créer des fils jusqu'à corePoolSize quand il est lancé.
  2. Il faut demander jusqu'à corePoolSize et laisser fil pour traiter la tâche.
  3. S'il y a plus de demandes entrantes alors que tous les threads sont occupés, ThreadPoolTaskExecutor est de commencer à faire la queue en file d'attente les demande interne. Cela peut être problématique car cette taille de file d'attente sera Integer.MAX_VALUE par défaut si vous ne spécifiez pas la file d'attente queueCapacité.
  4. Demande ajoutée à # 3 sera exécuté par fil quand il y a des threads disponibles dans la piscine.
  5. Si les demandes sont et continuent d'affluer toutes les discussions sont file d'attente & occupé est pleine, le ThreadPoolTaskExecutor commence à créer de nouvelles discussions jusqu'à MaxPoolSize pour traiter les demandes.
  6. Si les demandes sur ces (nombre de threads augmenté + taille de la file d'attente), alors la tâche sera rejetée ou suivant la politique que vous avez spécifiée.

Le problème ici, je pense est, soit 1) votre consommation est assez ou 2) vous demande empilage trop lentement, donc un fil que vous spécifiez avec corePoolSize était assez rapide pour traiter nouvelles requêtes entrantes + tâche en file d'attente sans permettant à ThreadPoolTaskExecutor de créer de nouveaux threads. Je suis assez sûr que si vous le poussez plus fort ou que vous ajustez la capacité de la file d'attente avec un petit nombre (comme 5 ~ 10), vous verrez que le nombre de threads augmente.

28

essayez ceci:

<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> 
  • Cela va créer 10 fils au moment de l'initialisation.
  • Si tous les 10 threads sont occupés et une nouvelle tâche s'affiche, alors il gardera les tâches dans la file d'attente.
  • Si la file d'attente est pleine, elle créera le 11ème thread et ira jusqu'à 25.
  • Puis lancera TaskRejected Exception.
+1

Le problème avec cette réponse est qu'elle n'explique pas pourquoi elle se passe. C'est pourquoi l'autre réponse obtient la coche pour moi. Ensuite, il serait bon que la réponse acceptée explique comment résoudre le problème. – Gray

Questions connexes