2010-08-02 64 views
0

[我的设置:Java EE 6的应用,与EJB3.1,CDI /焊缝,JSF2 Glassfish上运行3.0.1]如何使用EJB3.1 @Asynchronous时避免ConcurrentModificationExceptions

我读了一些文章EJB3.1中的新的@Asynchronous方法,但没有一个提到了异步方法的危害以及你真正必须关心的问题。

在我的应用程序中,我有@Asynchronous电子邮件服务,发送大量邮件。我从CDI/Weld Bean调用这个服务。在我的测试过程中,我经常遇到ConcurrentModificationExceptions,但直到现在,我并不真正了解它有时会崩溃的位置和原因。

为了表明我有多么豆类大致模样,最重要的部分:

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

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

在我CDI豆,我使用这个EJB这样的(暴露进步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); 
    (...) 
    } 
} 

我只是想问一般情况:我在这里做的事情是否完全错误(范围,注射,使用未来)?使用@Asynchronous方法时,我必须关心什么,以避免ConcurrentModificationExceptions?

我正在将Email作为EJB注入。将整个EmailEJB异步并注入@Inject @Asynchronous会更好吗?有什么区别?

任何提示欢迎!

回答

0

我最大的失败是为我的CDI bean使用Session Scope。这只允许一次异步EJB的一个实例 - 可以导致ConcurrentModificationException(我认为它在我重新指定Future值的地方)。

所以@Asynchronous方法/类似乎是ConversationScope的理想选择。相应地更改了我的CDI bean,到目前为止没有例外。

2

你对异步方法的使用应该没问题,但我不知道你是否真的希望它是@Stateful。在@Asynchronous方法被调用时@Stateful bean内部的状态听起来像是在另一个线程中被修改(或迭代)的状态。如果@Stateful bean有一个List字段并且对该列表的引用在@Stateful bean之外传递并被使用,则会发生这种情况。如果调用者线程和异步线程都使用了列表,那么除非将其更改为某种并发列表,否则这将是一件非常糟糕的事情。

如果确实在@Stateful bean中有状态,最好将它解压缩到一个具有最终(不可变)字段的值对象中,并将其传递给@Asynchronous @Singleton方法 - 可能使用@Lock( READ)如果异步方法不更新@Singleton中的任何状态。