Quelle est la méthode recommandée pour générer des threads à partir d’un servlet dans Tomcat

Probablement une répétition! J’utilise Tomcat comme serveur et je veux savoir quelle est la meilleure façon de générer des threads dans le servlet avec des résultats déterministes. J’exécute des mises à jour de longue durée à partir d’une action de servlet et souhaite que la demande soit complète et que les mises à jour soient effectuées en arrière-plan. Au lieu d’append un middleware de messagerie comme RabbitMQ, je pensais pouvoir créer un thread capable de s’exécuter en arrière-plan et de terminer dans son temps. J’ai lu dans d’autres threads SO que le serveur termine les threads générés par le serveur afin de bien gérer les ressources.

Existe-t-il un moyen recommandé de générer des threads, des tâches en arrière-plan lors de l’utilisation de Tomcat. J’utilise également Spring MVC pour l’application.

Votre pari le plus sûr consiste à utiliser un pool de threads large applicat avec un nombre maximum de threads, afin que les tâches soient mises en queue chaque fois que cela est nécessaire. L’ ExecutorService est très utile à cet égard.

Lors du démarrage de l’application ou de l’initialisation du servlet, utilisez la classe Executors :

 executor = Executors.newFixedThreadPool(10); // Max 10 threads. 

Ensuite, pendant le service du servlet (vous pourriez ignorer le résultat pour le cas qui ne vous intéresse pas):

 Future result = executor.submit(new CallableTask()); 

Enfin, lors de l’arrêt de l’application ou de la destruction du servlet:

 executor.shutdownNow(); // Returns list of undone tasks, for the case that. 

Vous pourriez peut-être utiliser une implémentation CommonJ WorkManager (JSR 237) comme Foo-CommonJ :

CommonJ – JSR 237 Timer & WorkManager

Foo-CommonJ est une implémentation JSR 237 Timer et WorkManager. Il est conçu pour être utilisé dans des conteneurs qui ne sont pas fournis avec leur propre implémentation – principalement des conteneurs de servlets simples tels que Tomcat . Il peut également être utilisé sur des serveurs d’applications Java EE entièrement équipés qui ne disposent pas d’une API WorkManager ou d’une API non standard telle que JBoss.

Pourquoi utiliser WorkManagers?

Le cas d’utilisation courant est qu’un Servlet ou JSP doit regrouper des données provenant de plusieurs sources et les afficher sur une seule page. Faire votre propre threading dans un environnement géré tel qu’un conteneur J2EE est inapproprié et ne devrait jamais être fait dans le code de niveau de l’application . Dans ce cas, l’API WorkManager peut être utilisée pour récupérer les données en parallèle.

Installer / Déployer CommonJ

Le déploiement du fournisseur de ressources JNDI en fonction. Cette implémentation est fournie avec une classe Factory qui implémente l’interface javax.naming.spi.ObjectFactory , ce qui la rend facilement déployable dans les conteneurs les plus javax.naming.spi.ObjectFactory . Il est également disponible en tant que service JBoss. plus…

Mise à jour: Juste pour clarifier, voici ce que les utilitaires de concurrence pour l’aperçu de Java EE (ressemble à ceci est le successeur de JSR-236 et JSR-237) écrit sur les threads non gérés:

2.1 Threads gérés par conteneur et non gérés

Les serveurs d’applications Java EE nécessitent une gestion des ressources afin de centraliser l’administration et de protéger les composants de l’application contre la consommation de ressources inutiles. Cela peut être réalisé grâce à la mise en commun des ressources et à la gestion du cycle de vie d’une ressource. L’utilisation d’utilitaires de concurrence Java SE tels que l’API java.util.concurrency , java.lang.Thread et java.util.Timer dans un composant d’application serveur tel qu’un servlet ou un EJB sont problématiques car le conteneur et le serveur ne connaissent pas ces ressources .

En étendant l’API java.util.concurrent , les serveurs d’applications et les conteneurs Java EE peuvent prendre connaissance des ressources utilisées et fournir le contexte d’exécution approprié pour les opérations asynchrones .

Ceci est en grande partie réalisé en fournissant des versions gérées des interfaces prédominantes java.util.concurrent.ExecutorService .

Donc, rien de nouveau IMO, le “vieux” problème est le même, les threads non gérés sont toujours des threads non gérés:

  • Ils sont inconnus du serveur d’applications et n’ont pas access aux informations contextuelles Java EE.
  • Ils peuvent utiliser des ressources à l’arrière du serveur d’applications et, sans aucune capacité d’administration à contrôler leur nombre et leur utilisation des ressources, cela peut affecter la capacité du serveur d’applications à récupérer des ressources ou à les arrêter normalement.

Les références

  • Site d’intérêt sur les access simultanés pour Java EE
  • Utilitaires de simultanéité pour Java EE Preview (PDF)

Spring prend en charge la tâche asynchrone (dans votre cas, qui dure longtemps) via la planification de spring. Au lieu d’utiliser les threads Java directement, je suggère de l’utiliser avec Quartz.

Recours:

  • Référence de spring: Chapitre 23

Ssortingctement parlant, vous n’êtes pas autorisé à générer des threads selon les spécifications Java EE. J’envisagerais également la possibilité d’une attaque par déni de service (délibérée ou non) si plusieurs demandes arrivent en même temps.

Une solution de middleware serait certainement plus robuste et conforme aux normes.

Je sais que c’est une vieille question, mais les gens continuent à le demander, essayant de faire ce genre de choses (générer explicitement des threads lors du traitement d’une requête de servlet) … C’est une approche très imparfaite pour plusieurs raisons. .. Se contenter d’indiquer que les conteneurs Java EE ne sont pas satisfaits, même si c’est généralement vrai …

Plus important encore, on ne peut jamais prédire combien de requêtes simultanées le servlet recevra à un moment donné. Une application Web, une servlet, par définition, est censée être capable de traiter plusieurs requêtes sur le sharepoint terminaison donné à la fois. Si vous programmez une requête de logique de traitement pour lancer explicitement un certain nombre de threads simultanés, vous risquez de faire face à une situation inévitable, à savoir le manque de threads disponibles et l’étouffement de votre application. Votre exécuteur de tâches est toujours configuré pour fonctionner avec un pool de threads limité à une taille raisonnable. Le plus souvent, il n’est pas plus grand que 10-20 (vous ne voulez pas que trop de threads exécutent votre logique – en fonction de la nature de la tâche, des ressources en compétition, du nombre de processeurs sur votre serveur, etc.) , votre gestionnaire de requêtes (par exemple, la méthode du contrôleur MVC) appelle une ou plusieurs méthodes annotées @ Async (auquel cas Spring extrait l’exécuteur de la tâche et vous simplifie la tâche) ou utilise explicitement l’exécuteur de tâches. Lorsque votre code s’exécute, il commence à saisir les threads disponibles dans le pool. C’est bien si vous traitez toujours une demande à la fois sans aucune demande de suivi immédiate. (Dans ce cas, vous essayez probablement d’utiliser la mauvaise technologie pour résoudre votre problème.) Cependant, si c’est une application Web exposée à des clients arbitraires (ou même connus) qui risquent de manipuler le noeud final avec des requêtes, vous devrez épuiser rapidement le pool de threads, et les requêtes commenceront à s’accumuler, en attendant que les threads soient disponibles. Pour cette seule raison, vous devez réaliser que vous êtes peut-être sur la mauvaise voie si vous envisagez une telle conception.

Une meilleure solution pourrait être de mettre en scène les données à traiter de manière asynchrone (qui pourrait être une file d’attente ou tout autre type de magasin de données temporaire / de transfert) et de renvoyer la réponse. Avoir une application externe, indépendante, ou même plusieurs instances (déployées en dehors de votre conteneur Web) interroge le ou les systèmes d’extrémité de transit et traite les données en arrière-plan, en utilisant éventuellement un nombre fini de threads concurrents. Une telle solution vous offre non seulement l’avantage d’un traitement asynchrone / simultané, mais évoluera également car vous pourrez exécuter autant d’instances de ce type que vous le souhaitez, et elles pourront être dissortingbuées, en pointant vers le noeud final intermédiaire. HTH

Depuis le spring 3, vous pouvez utiliser les annotations @Async:

 @Service public class smg { ... @Async public getCounter() {...} } 

avec et dans le fichier de contexte

Veuillez vous référer à ce tutoriel: http://spring.io/blog/2010/01/05/task-scheduling-simplifications-in-spring-3-0/

Fonctionne très bien pour moi sur Tomcat7 et vous n’avez pas à gérer un pool de threads.