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