Потокобезопасен ли поток HttpSession, являются ли потокобезопасные операции set / get Attribute? - PullRequest
52 голосов
/ 06 марта 2009

Кроме того, должен ли задаваемый объект быть потокобезопасным, чтобы гарантировать, что мы знаем, какое состояние объекта, сохраненного в сеансе, известно.

Кроме того, я читал в Интернете, что некоторые предлагают использовать:

synchronized(session) {
  session.setAttribute("abc", "abc");
}

Это действительное предложение?

Ответы [ 6 ]

63 голосов
/ 06 марта 2009

Servlet 2.5 spec:

Несколько сервлетов, выполняющих запрос потоки могут иметь активный доступ к тот же объект сеанса в то же время. Контейнер должен гарантировать, что манипулирование внутренними данными структуры, представляющие сессию Атрибуты выполняются в Безопасный способ. Разработчик имеет ответственность за безопасность потоков доступ к объектам атрибута самих себя. Это защитит коллекция атрибутов внутри HttpSession объект из параллельного доступ, исключая возможность для приложения, чтобы вызвать это коллекция испортилась.

Это безопасно:

// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);

Это , а не безопасно:

HttpSession session = request.getSession();
Integer n = (Integer) session.getAttribute("foo");
// not thread safe
// another thread might be have got stale value between get and set
session.setAttribute("foo", (n == null) ? 1 : n + 1);

Это , а не гарантированно безопасно:

// no guarantee that same instance will be returned,
// nor that session will lock on "this"
HttpSession session = request.getSession();
synchronized (session) {
  Integer n = (Integer) session.getAttribute("foo");
  session.setAttribute("foo", (n == null) ? 1 : n + 1);
}

Я видел, как пропагандируется этот последний подход (в том числе в книгах J2EE), но он не гарантированно работает по спецификации сервлета. Вы можете использовать идентификатор сеанса для создания мьютекса , но должен быть лучший подход.

36 голосов
/ 06 марта 2009
4 голосов
/ 06 марта 2009

Нет. И поскольку вы не хотите, чтобы один и тот же клиент (с сеансом) выполнял параллельные запросы, вы должны сериализовать эти запросы, как AbstractController в Spring MVC

3 голосов
/ 06 марта 2009

В некоторой степени это зависит от дизайна вашего клиента.

Есть ли в вашем веб-дизайне возможность для одного клиента иметь несколько ожидающих одновременных запросов, используя один и тот же сеанс HTTP? Это кажется трудным, если вы не привязываете один HTTP-сеанс к нескольким сокетам. (aka, AJAX) Если не делать этого, HTTP-доступ данного клиента будет однопоточным, если речь идет о сервере, что означает, что отдельный сеанс является поточно-безопасным.

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

2 голосов
/ 06 марта 2009

Это не так, но в большинстве случаев ваши клиенты будут иметь к ним доступ только через один поток.

У разных клиентов будут разные потоки, и у каждого будет свой собственный сеанс.

Как указывает Эдди, одна из ситуаций, когда вы можете столкнуться с двумя потоками, обращающимися к одному и тому же сеансу, - два вызова ajax пытаются изменить один и тот же атрибут сеанса. В противном случае у вас не будет проблем.

1 голос
/ 06 марта 2009

Сеанс не является потокобезопасным, и ни методы get, ни set не гарантированно являются потокобезопасными. В общем случае в контейнере сервлетов вы должны предполагать, что находитесь в многопоточной среде, и никакие инструменты не являются безопасными.

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

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

...