web-dev-qa-db-fra.com

Conteneur Jboss Java EE et un ExecutorService

J'ai une application Java autonome qui utilisait ExecutorService pour traiter plusieurs tâches en parallèle.

 ExecutorService es = Executors.newFixedThreadPool(10);

Je souhaite maintenant réutiliser la même solution dans un bean EJB, mais je ne sais pas comment initialiser correctement le ThreadPool, car je laisserais normalement le conteneur Java EE pour contrôler toutes les ressources de thread. Puis-je simplement utiliser le même code ou existe-t-il un autre moyen correct d'obtenir un pool de threads gérés par Jboss?

25
emeraldjava

La bonne façon de procéder dans votre EJB consiste à utiliser ManagedExecutorService, composant de l'API Concurrency Utils (Java EE7). Vous ne devez pas utiliser ExecutorService faisant partie de Java.util.concurrent dans votre code d'entreprise.

En utilisant 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 définirons le travail que nous souhaitons 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();
    }
}

Ensuite, nous devons appeler la tâche en la passant à la méthode submit () de ManagedExecutorService.

@Stateless
public class ReportBean {

    @Resource
    private ManagedExecutorService executorService;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Future<Report> future = executorService.submit(reportTask);
    }
}
28
Chris Ritchie

Avertissement obligatoire: il est déconseillé de créer vos propres threads sur un serveur d'applications Java EE (même Tomcat), car cela peut poser un problème de performances considérable et, dans la plupart des cas, empêcher la fonctionnalité de conteneur, telle que JNDI Les nouveaux threads ne sauront pas à quelle application ils appartiennent, le chargeur de classe de contexte Thread ne sera pas défini et de nombreux autres problèmes cachés.

Heureusement, il existe un moyen de faire gérer le pool de threads via le serveur Java EE 6 @Asynchronous et ce modèle de conception intelligent. Portable sur tout 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();
    }
}

Ensuite, vous pouvez faire référence à ce bean ailleurs dans votre application via une injection de dépendance simple (si le composant référent est un servlet, un écouteur, un filtre, un autre bean EJB, JSF géré).

@EJB
private Executor executor;

Ensuite, utilisez 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");
26
David Blevins

Eh bien ... La solution de David n'a pas fonctionné pour moi pour les raisons suivantes:

  1. Le compilateur a critiqué le fait que Java.util.concurrent n'est pas autorisé ... ce qui est logique dans la portée de JBOSS. 
  2. Aussi: public STATIC class ...? Lisez ceci: Pourquoi ne pouvez-vous pas déclarer une classe statique en Java?

Voici ce que j'ai fait:
Mon installation:
- JBOSS AS 7.1.1
- Java 1.6
- RHEL
- Exécuter l'exemple avec Gradle et Arquillian :

@Stateless
public class ExecutorBean {
    @Asynchronous
    public void execute(Runnable command) {
        command.run();    
    }
}

Ensuite, votre client ressemble à ceci:

@EJB ExecutorBean eb;
@Test
public void testExecutorBean() {
    eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff());
    assertFalse(!true);
}

Attention cependant: dans mon fichier standalone.xml (ou en général mon fichier de configuration pour JBOSS, j'ai une section 'thread-pools'. Regardez-la (si vous utilisez JBOSSAS) et modifiez les valeurs. Modifiez-les. Comment ça se comporte. Quand j'utilise des threads avec des tests arquillian, je reçois des threads qui sont tués même si mon temps de maintien est très élevé. Je pense que cela a à voir avec la façon dont micros déploie arquillian. pendant que les tests sont en cours d'exécution ... du moins, c'est ce que je pense observer. Par contre, tous les fils finis se sont bien comportés en ce sens qu'ils ont terminé leurs tâches/opérations.

J'espère que ce post aide! 

5
easyDaMan

Avant EE7, vous souhaiterez peut-être utiliser WorkManager à partir de JSR 237.

http://docs.Oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html

Cette spécification est actuellement retirée, mais certains serveurs d'applications l'implémentent. J'utilise l'implémentation ibm dans WebSphere 8.5 - IBM WorkManager . C'est une ressource entièrement gérée, disponible dans la console d'administration. Veuillez noter que l'interface n'est pas 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 conscient de Commonj Workmanager

2
Vlad

Si vous utilisez JBoss, vous pouvez utiliser org.jboss.seam.async.ThreadPoolDispatcher. 

ThreadPoolDispatcher est complètement géré.

Pour d'autres classes managées utiles, voir le package: org.jboss.seam.async.

0
marciowb