web-dev-qa-db-fra.com

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 j'aimerais que la demande se termine et que les mises à jour se produisent en arrière-plan. Au lieu d'ajouter un middleware de messagerie comme RabbitMQ, j'ai pensé que je pourrais générer un thread qui pourrait s'exécuter en arrière-plan et terminer en son temps. J'ai lu dans d'autres threads SO que le serveur termine les threads générés par le serveur afin qu'il gère bien les ressources.

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

48
Ritesh M Nayak

Votre pari le plus sûr est d'utiliser un pool de threads large d'application avec un nombre maximum de threads, afin que les tâches soient mises en file d'attente chaque fois que nécessaire. ExecutorService est très utile à cet égard.

Au démarrage de l'application ou à l'initialisation du servlet, utilisez la classe Executors :

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

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

Future<ReturnType> 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.
44
BalusC

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

CommonJ - Minuterie JSR 237 et 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 livrés avec leur propre implémentation - principalement des conteneurs de servlet simples comme Tomcat . Il peut également être utilisé dans des serveurs d'applications Java EE entièrement équipés qui ne disposent pas d'une API WorkManager ou d'une API non standard comme JBoss).

Pourquoi utiliser WorkManagers?

Le cas d'utilisation courant est qu'un servlet ou JSP doit regrouper les données de plusieurs sources et les afficher sur une seule page. Faire votre propre threading dans un environnement géré comme un conteneur J2EE est inapproprié et ne devrait jamais être fait dans le code de niveau 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 des ressources JNDI dépend du fournisseur. Cette implémentation est livrée avec une classe Factory qui implémente le javax.naming.spi.ObjectFactory l'interface avec le rend facilement déployable dans les conteneurs les plus populaires. Il est également disponible en tant que service JBoss. plus...

Mise à jour: Juste pour clarifier, voici ce que les tilitaires de concurrence pour Java EE Preview (on dirait que c'est le successeur de JSR-236 & JSR-237) écrit sur les threads non gérés:

2.1 Threads gérés par conteneur ou 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 d'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. Utilisation de Java SE utilitaires de concurrence tels que Java.util.concurrency API, 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 n'ont aucune connaissance de ces ressources .

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

Cet objectif est largement atteint en fournissant des versions gérées de la version prédominante Java.util.concurrent.ExecutorService interfaces.

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 accès 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 l'utilisation des ressources, cela peut affecter la capacité du serveur d'applications à récupérer les ressources en cas d'échec ou à s'arrêter correctement.

Les références

30
Pascal Thivent

Spring prend en charge la tâche asynchrone (dans votre cas, longue durée) via la planification du printemps. Au lieu d'utiliser Java threads direct, je suggère de l'utiliser avec Quartz.

Recours:

7
Jaydeep Patel

Je sais que c'est une vieille question, mais les gens continuent de la poser, essayant de faire ce genre de chose (engendrant explicitement des threads lors du traitement d'une demande de servlet) tout le temps ... C'est une approche très imparfaite - pour plus d'une raison. .. Il suffit de déclarer que Java EE désapprouvent une telle pratique ne suffisent pas, bien que généralement vrai ...

Plus important encore, on ne peut jamais prédire le nombre de demandes simultanées que le servlet recevra à un moment donné. Une application Web, une servlet, par définition, est censée être capable de traiter plusieurs demandes à la fois sur le point de terminaison donné. Si vous programmez, vous demandez à la logique de traitement de lancer explicitement un certain nombre de threads simultanés, vous risquez de faire face à une situation presque inévitable de manquer de threads disponibles et d'étouffer votre application. Votre exécuteur de tâches est toujours configuré pour fonctionner avec un pool de threads limité à une taille raisonnable finie. Le plus souvent, il n'est pas supérieur à 10-20 (vous ne voulez pas que trop de threads exécutent votre logique - selon la nature de la tâche, les ressources pour lesquelles ils se disputent, le nombre de processeurs sur votre serveur, etc.) Disons , votre gestionnaire de requêtes (par exemple la méthode du contrôleur MVC) invoque une ou plusieurs méthodes annotées @ Async (auquel cas Spring résume l'exécuteur de tâche et vous facilite la tâche) ou utilise explicitement l'exécuteur de tâche. Lorsque votre code s'exécute, il commence à récupérer les threads disponibles dans le pool. C'est très bien si vous traitez toujours une demande à la fois sans demande de suivi immédiat. (Dans ce cas, vous essayez probablement d'utiliser la mauvaise technologie pour résoudre votre problème.) Cependant, si c'est une application Web qui est exposée à des clients arbitraires (ou même connus) qui peuvent marteler le point final avec des demandes, vous le ferez épuiser rapidement le pool de threads, et les demandes commenceront à s'accumuler, en attendant que les threads soient disponibles. Pour cette seule raison, vous devez vous rendre compte que vous pouvez être sur une mauvaise voie - si vous envisagez une telle conception.

Une meilleure solution peut être de étape 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/intermédiaire) et de renvoyer la réponse. Demandez à une application externe indépendante ou même à plusieurs instances de celle-ci (déployée en dehors de votre conteneur Web) d'interroger le ou les points d'extrémité intermédiaires et de traiter les données en arrière-plan, en utilisant éventuellement un nombre fini de threads simultanés. Non seulement une telle solution vous donnera l'avantage d'un traitement asynchrone/simultané, mais elle évoluera également car vous pourrez exécuter autant d'instances de ce poller que vous en avez besoin, et elles peuvent être distribuées, pointant vers le point de terminaison intermédiaire. HTH

4
cvnew

À strictement parler, vous n'êtes pas autorisé à générer des threads conformément à la spécification Java EE. Je considérerais également la possibilité d'une attaque par déni de service (délibérée ou non) si plusieurs demandes arrivent à une fois que.

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

4
dty

Depuis Spring 3, vous pouvez utiliser les annotations @Async:

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

avec <context:component-scan base-package="ch/test/mytest"> et <task:annotation-driven/> 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 besoin de gérer un pool de threads.

1
Nereis