ОБНОВЛЕНИЕ: Решение сразу после вопроса.
Обычно синхронизация представляет собой сериализацию параллельных запросов внутри JVM, например.
private static final Object LOCK = new Object();
public void doSomething() {
...
synchronized(LOCK) {
...
}
...
}
При рассмотрении веб-приложений некоторая синхронизация в области «JVM global» может стать узким местом в производительности, и синхронизация только в пределах пользовательской HttpSessionбудет иметь больше смысла.
Возможен ли следующий код? Я сомневаюсь, что синхронизация на объекте сеанса — хорошая идея, но было бы интересно услышать ваши мысли.
HttpSession session = getHttpServletRequest().getSession();
synchronized (session) {
...
}
Ключевой вопрос:
Гарантируется ли, что объект сеанса является одним и тем же экземпляромдля всех потоков, обрабатывающих запросы от одного и того же пользователя?
Кажется, что сам объект сеанса не всегда один и тот же, поскольку он зависит от реализации контейнера сервлета (Tomcat, Glassfish, ...) и getSession()
метод может возвращать только экземпляр оболочки.
Поэтому рекомендуется использовать пользовательскую переменную, хранящуюся в сеансе, в качестве объекта блокировки.
Вот мое предложение по коду, отзывы приветствуются:
где-то в вспомогательном классе, например.MyHelper
:
private static final Object LOCK = new Object();
public static Object getSessionLock(HttpServletRequest request, String lockName) {
if (lockName == null) lockName = "SESSION_LOCK";
Object result = request.getSession().getAttribute(lockName);
if (result == null) {
// only if there is no session-lock object in the session we apply the global lock
synchronized (LOCK) {
// as it can be that another thread has updated the session-lock object in the meantime, we have to read it again from the session and create it only if it is not there yet!
result = request.getSession().getAttribute(lockName);
if (result == null) {
result = new Object();
request.getSession().setAttribute(lockName, result);
}
}
}
return result;
}
и затем вы можете его использовать:
Object sessionLock = MyHelper.getSessionLock(getRequest(), null);
synchronized (sessionLock) {
...
}
Есть комментарии по этому решению?