JBoss Java EE container et un ExecutorService
j'ai une application java autonome qui utilisait L'Exécutorservice pour traiter un certain nombre de tâches en parallèle
ExecutorService es = Executors.newFixedThreadPool(10);
je veux maintenant réutiliser la même solution dans un bean EJB mais je ne sais pas comment initialiser correctement le ThreadPool, puisque je quitterais normalement le conteneur Java EE pour contrôler toutes les ressources thread. Puis-je utiliser le même code ou y a-t-il une autre façon correcte d'obtenir un pool de threads géré par Jboss?
5 réponses
la bonne façon de le faire dans votre EJB est d'utiliser le ManagedExecutorService, qui fait partie de L'API Utils (Java EE7). Vous ne devriez pas utiliser un Exécutorservice qui fait partie du java.util.concurrent dans votre code d'entreprise.
en utilisant le ManagedExecutorService votre nouveau thread sera créé et géré par le conteneur.
L'exemple suivant est tiré de mon site ici .
pour créer un nouveau thread à l'aide d'un ManagedExecutorService, créez d'abord un objet de tâche qui implémente Callable. Dans la méthode call () nous allons définir le travail que nous voulons effectuer dans un thread séparé.
public class ReportTask implements Callable<Report> {
Logger logger = Logger.getLogger(getClass().getSimpleName());
public Report call() {
try {
Thread.sleep(3000);
catch (InterruptedException e) {
logger.log(Level.SEVERE, "Thread interrupted", e);
}
return new Report();
}
}
alors nous devons invoquer la tâche en la passant bien à la méthode submit() du ManagedExecutorService.
@Stateless
public class ReportBean {
@Resource
private ManagedExecutorService executorService;
public void runReports() {
ReportTask reportTask = new ReportTask();
Future<Report> future = executorService.submit(reportTask);
}
}
avertissement obligatoire: créer vos propres threads dans un serveur d'application Java EE (même Tomcat) est déconseillé car cela peut être un énorme problème de performance et dans la plupart des cas, cela empêchera les fonctionnalités de conteneur, telles que JNDI, de fonctionner. Les nouveaux threads ne sauront pas à quelle application ils appartiennent, le contexte Thread classloader ne sera pas défini et beaucoup d'autres problèmes cachés.
heureusement, il y a un moyen D'obtenir le serveur Java EE pour gérer le thread pool via le Java EE 6 @Asynchronous
et ce design astucieux. Portable sur n'importe quel serveur certifié Java EE 6.
créez cet EJB dans votre application.
package org.superbiz;
import javax.ejb.Asynchronous;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
@Stateless(name="Executor")
public class ExecutorBean implements Executor {
@Asynchronous
@Override
public void execute(Runnable command) {
command.run();
}
}
alors vous pouvez vous référer à ce haricot ailleurs dans votre application par simple injection de dépendance (si le composant de référence est un Servlet, un écouteur, un filtre, un autre EJB, JSF managed bean).
@EJB
private Executor executor;
puis utilisez le Executor
comme d'habitude.
si le composant N'est pas un autre composant Java EE, vous pouvez rechercher le bean via:
InitialContext initialContext = new InitialContext();
Executor executor = (Executor) initialContext.lookup("java:module/Executor");
bien... La solution de David n'a pas fonctionné pour moi pour les raisons suivantes:
- compilateur était en train de râler autour de cette java.util.simultanées n'est pas autorisé... ce qui est un peu logique dans le cadre de JBOSS.
- également: public STATIC class...? Lisez ceci: pourquoi ne pouvez-vous pas déclarer une classe comme statique en Java?
voici ce que j'ai fait:
Mon installation:
- JBOSS AS 7.1.1
- La version 1.6 de Java
- RHEL
- Exemple avec Gradle et Arquillian :
@Stateless
public class ExecutorBean {
@Asynchronous
public void execute(Runnable command) {
command.run();
}
}
alors votre client ressemble à ceci:
@EJB ExecutorBean eb;
@Test
public void testExecutorBean() {
eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff());
assertFalse(!true);
}
attention cependant: dans mon standalone.xml (ou généralement mon fichier de configuration pour JBOSS j'ai une section 'thread-pools'. Avoir un regardez - le (si vous vous trouvez à utiliser JBOSSAS) et bricoler avec les valeurs là-bas. Savoir comment il se comporte. Quand j'utilise des threads avec des tests arquilliens, j'obtiens des threads qui sont tués bien que mon temps de garde soit très élevé. Je pense que ça a à voir avec comment arquillian microdeploys. Quand arquillian termine tous les threads non finis sont tués qui étaient en cours d'exécution pendant que les tests sont en cours d'exécution... du moins, c'est ce que je pense observer. D'un autre côté, tous les fils finis se sont en fait bien comportés dans ce sens qu'ils ont terminé leurs tâches/opérations.
Espère que ce post vous sera utile!
avant EE7, vous pouvez utiliser WorkManager de JSR 237
http://docs.oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html
cette spécification est actuellement retirée, certains serveurs app l'implémentent toujours. J'utilise ibm implementation dans WebSphere 8.5 - IBM WorkManager . Il s'agit d'une ressource entièrement gérée, disponible dans la console d'administration. Veuillez noter qu'il n'est pas interface-compatible avec Oracle.
voici un exemple pour la version IBM:
@Resource(lookup = "wm/default")
WorkManager workManager;
public void process() {
try {
ArrayList<WorkItem> workItems = new ArrayList<WorkItem>();
for (int i = 0; i < 100; i++) {
// submit 100 jobs
workItems.add(workManager.startWork(new Work() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " Running");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void release() {
System.out.println(Thread.currentThread().getName() + " Released");
}
}));
}
// wait for all jobs to be done.
workManager.join(workItems, WorkManager.JOIN_AND, 100000);
} catch (WorkException e) {
e.printStackTrace();
}
}
aussi je suis au courant de Commonj Workmanager .
si vous utilisez JBoss, vous pouvez utiliser org.jboss.couture.asynchrone.ThreadPoolDispatcher.
ThreadPoolDispatcher est entièrement géré.
pour d'autres classes gérées utiles, voir le paquet: org.jboss.couture.asynchrone.