UPDATE: Решение сразу после вопроса.
Вопрос:
Обычно синхронизация выполняет сериализацию параллельных запросов в 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) {
...
}
Любые комментарии к этому решению?