2010-08-02 2 views
0

[Mon installation: application Java EE 6, avec EJB3.1, CDI/Weld, JSF2 fonctionnant sur Glassfish 3.0.1]Comment éviter ConcurrentModificationExceptions lors de l'utilisation EJB3.1 @Asynchronous

J'ai lu quelques articles sur la nouvelles méthodes @Asynchronous dans EJB3.1, mais aucune d'entre elles n'a mentionné les dangers des méthodes asynchrones et ce dont vous avez vraiment besoin.

Dans mon application, je reçois un service de courrier électronique asynchrone, en envoyant beaucoup de mails. J'appelle ce service d'un bean CDI/Weld. Au cours de mes tests, j'ai souvent vécu des Exceptions ConcurrentModification, mais jusqu'à présent, je ne comprends pas vraiment où et pourquoi il se bloque parfois.

Juste pour montrer comment mes haricots ressemblent à peu près comme, les parties importantes:

@Stateful @LocalBean 
public class EmailEJB { 
    //... Injections 

    @Asynchronous 
    public Future<Integer> sendEmails(User user, Message message) { 
    // ... send mails 
    return new AsyncResult<Integer>(1); 
    } 
} 

Dans mon CDI-Bean, j'utilise ce EJB comme celui-ci (exposant les progrès à JSF2):

@Named @SessionScoped 
public class MessageManager { 
    @EJB 
    public EmailEJB emailEJB; 

    public FutureEJB<Integer> progress; 

    public Integer getProgress() { 
    if (progress == null) return 0; 
    else { 
     return progress.get(); 
    } 
    } 

    public String sendMessage() { 
    (...) 
    progress = emailEJB.sendEmails(user, message); 
    (...) 
    } 
} 

Je voulais juste demander en général: est-ce que je fais quelque chose de complètement faux ici (Scopes, injections, using Future)? De quoi ai-je besoin lorsque j'utilise des méthodes @Asynchrones, pour éviter les exceptions ConcurrentModification? J'injecte l'email comme un EJB. Sera-t-il préférable de rendre l'ensemble EmailEJB asynchrone et de l'injecter avec @Inject @Asynchronous? Quelle serait la différence?

Les conseils sont les bienvenus!

Répondre

0

Mon plus gros échec a été d'utiliser Session Scope pour mon bean CDI. Cela ne permet qu'une seule instance de l'EJB asynchrone à la fois, ce qui aboutit à l'exception ConcurrentModificationException (je pense que c'est à un point où je réattribue une valeur Future).

Ainsi, les méthodes/classes asynchrones semblent être un candidat idéal pour ConversationScope. J'ai changé mon bean CDI en conséquence, sans exception jusqu'à présent.

2

Votre utilisation de la méthode asynchrone aurait dû être bonne, même si je me demande si vous voulez vraiment qu'elle soit @Stateful. Des sons comme l'état à l'intérieur du bean @Stateful sont en cours de modification (ou itérés) dans un autre thread lorsque la méthode @Asynchronous est appelée. Cela peut arriver si le bean @Stateful a un champ List et qu'une référence à cette liste est passée en dehors du bean @Stateful et utilisée. Si le thread appelant et le thread asynchrone utilisaient tous les deux la liste, ce serait une très mauvaise chose à moins que vous le changiez en une liste concurrente de quelque sorte. Si vous avez un état dans le bean @Stateful, vous feriez mieux de l'extraire dans un objet de valeur qui a des champs finaux (immuables) et de le passer à une méthode @Singleton @Asynchrone - éventuellement avec @Lock (READ) si la méthode async ne met à jour aucun état dans @Singleton.

Questions connexes