Когда следует быть осторожным с многопоточностью в EJB? - PullRequest
1 голос
/ 30 ноября 2011

Я понимаю, что сервер приложений заботится о потоках, поэтому разработчик должен сосредоточиться только на бизнес-логике но рассмотрим пример. EJB без сохранения состояния имеет член типа CountManager.

@WebService
@Stateless
public class StatelessEJB {
  private CountManager countManager;
  ... 
  public void incrementCount() {countManager.incrementCount();}
  public int getCount(){return countManager.getCount();}
}

И CountManager

 public class CountManager {
    public void increaseCount() {
    // read count from database
    // increase count 
    // save the new count in database table. 
    }

    public int getCount() {
    // returns the count value from database.
    }
}

Разработчик должен подумать о многопоточности здесь. Если вы сделаете CountManager также EJB, я думаю, проблема не исчезнет. Какое общее руководство разработчик должен остерегаться?

Обновление: Поменял код. Предположим, что методы EJB представлены как веб-сервис, поэтому мы не можем контролировать порядок их вызова клиентом. Атрибут транзакции по умолчанию. Правильно ли работает этот код в многопоточном сценарии?

Ответы [ 2 ]

2 голосов
/ 01 декабря 2011

Тот факт, что EJB-потокобезопасен, не означает, что различные вызовы методов будут давать согласованные результаты.

EJB дает вам уверенность, что каждый метод в вашем конкретном экземпляре EJB будет выполняться ровно одним потоком . Это не спасет вас от доступа нескольких пользователей к различным экземплярам вашего EJB и опасности противоречивых результатов.

Ваш CountManager кажется обычным Java-классом, что означает, что вы держите состояние в EJB без сохранения состояния. Это нехорошо, и EJB-потокобезопасность в таком случае не защитит вас от чего-либо. Ваш объект может быть доступен через несколько экземпляров EJB одновременно.

Между первым вызовом метода вашего клиента StatelessEJB.incrementCount() (который запускает транзакцию - по умолчанию TransactionAttribute) и вторым вызовом метода клиента StatelessEJB.getCount() (который запускает новая транзакция) может произойти много вещей, и значение count может быть изменено.

Если бы вы изменили его на EJB, я не думаю, что вы были бы в большей безопасности. Если это SLSB, то он по-прежнему не может иметь никакого состояния. Если состояние не реализовано как переменная поля EJB, а извлекается из базы данных, то это определенно лучше, но все же - транзакция не является для вас реальной помощью, потому что ваш клиент WebService по-прежнему выполняет эти два метода по отдельности, что приводит к получению двух разных транзакций.

Простым решением будет:

  • использовать базу данных (без состояния в SLSB), которую можно синхронизировать с вашей транзакцией EJB,
  • выполнить оба эти метода в транзакции (например, метод incrementAndGet(-) для клиента WebService).

Чем вы можете быть уверены, что полученные результаты соответствуют.

2 голосов
/ 30 ноября 2011

Обратите внимание, что на самом деле проблема не в синхронизации или многопоточности, а в поведении транзакций.

Приведенный выше код, если он выполняется внутри EJB, позаботится об условиях гонки, делегировав поддержку транзакцийбаза данных.В зависимости от уровня изоляции и транзакционных атрибутов база данных может позаботиться о блокировке базовых таблиц, чтобы гарантировать, что информация остается согласованной, даже при одновременном доступе и / или изменениях.

...