代码之家  ›  专栏  ›  技术社区  ›  Wolkenarchitekt

使用EJB3.1@Asynchronous时如何避免ConcurrentModificationException

  •  0
  • Wolkenarchitekt  · 技术社区  · 14 年前

    [我的设置:JavaEE6应用程序,在Glassfish3.0.1上运行EJB3.1、CDI/Weld和JSF2]

    我读了一些关于EJB3.1中新的@Asynchronous方法的文章,但是没有一篇提到异步方法的危险以及您真正需要关心的问题。

    在我的应用程序中,我有一个@Asynchronous电子邮件服务,发送大量邮件。我从CDI/weldbean调用这个服务。在我的测试中,我经常遇到ConcurrentModificationExceptions,但直到现在我还不太明白它有时在哪里崩溃,为什么会崩溃。

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

    @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方法时,为了避免ConcurrentModificationException,我需要注意什么?

    欢迎任何提示!

    2 回复  |  直到 14 年前
        1
  •  2
  •   David Blevins    14 年前

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

    如果@Stateful bean中确实有state,那么最好将其提取到具有final(不可变)字段的value对象中,并将其传递给@Asynchronous@Singleton方法——如果async方法不更新@Singleton中的任何状态,则可能使用@Lock(READ)。

        2
  •  0
  •   Wolkenarchitekt    14 年前