Как избежать ConcurrentModificationExceptions при использовании EJB3.1 @Asynchronous - PullRequest
0 голосов
/ 02 августа 2010

[Моя настройка: приложение Java EE 6, с EJB3.1, CDI / Weld, JSF2, работающим на Glassfish 3.0.1]

Я прочитал несколько статей о новых методах @Asynchronous в EJB3.1, но ни один из них не упомянул об опасностях асинхронных методов и о том, что вам действительно нужно беспокоиться.

В моем приложении у меня есть служба @Asynchronous E-Mail, отправляющая много писем. Я вызываю эту услугу из 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);
    (...)
  }
}

Я просто хотел спросить в целом: делаю ли я здесь что-то совершенно не так (объемы, инъекции, использование Future)? О чем мне нужно заботиться при использовании @Asynchronous методов, чтобы избежать ConcurrentModificationExceptions?

Я внедряю письмо как EJB. Будет ли лучше сделать весь EmailEJB асинхронным и внедрить его с помощью @Inject @Asynchronous? Какая будет разница?

Любые советы приветствуются!

Ответы [ 2 ]

2 голосов
/ 04 августа 2010

Ваше использование асинхронного метода должно было быть нормальным, хотя мне интересно, действительно ли вы хотите, чтобы он был @Stateful.Похоже, что состояние внутри bean-компонента @Stateful изменяется (или повторяется) в другом потоке, когда вызывается метод @Asynchronous.Это может произойти, если бин @Stateful имеет поле «Список», а ссылка на этот список передается за пределы бина @Stateful и используется.Если бы поток вызывающей стороны и асинхронный поток использовали список, было бы очень плохо, если бы вы не изменили его на параллельный список какого-либо рода.

Если у вас есть состояние в bean-компоненте @Stateful, выможет быть, лучше извлечь его в объект значения, имеющий конечные (неизменяемые) поля, и передать его в метод @Asynchronous @Singleton - возможно, с помощью @Lock (READ), если асинхронный метод не обновляет состояние в @Singleton.

0 голосов
/ 03 августа 2010

Моей самой большой ошибкой было использование Session Scope для моего компонента CDI. Это позволяет только один экземпляр асинхронного EJB одновременно - вероятно, приводя к исключению ConcurrentModificationException (я думаю, что это в точке, где я переназначаю значение Future).

Таким образом, @ асинхронные методы / классы кажутся идеальным кандидатом для ConversationScope. Соответственно изменил мой CDI-бин, исключений пока нет.

...