2010-08-02 106 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中的任何狀態。