Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is synchronization within an HttpSession feasible?

UPDATE: Solution right after question.

Question:

Usually, synchronization is serializing parallel requests within a JVM, e.g.

private static final Object LOCK = new Object();  public void doSomething() {   ...   synchronized(LOCK) {     ...   }   ... } 

When looking at web applications, some synchronization on "JVM global" scope is maybe becoming a performance bottleneck and synchronization only within the scope of the user's HttpSession would make more sense.

Is the following code a possibility? I doubt that synchronizing on the session object is a good idea but it would be interesting to hear your thoughts.

HttpSession session = getHttpServletRequest().getSession(); synchronized (session) {   ... } 

Key Question:
Is it guaranteed that the session object is the same instance for all threads processing requests from the same user?

Summarized answer / solution:

It seems that the session object itself is not always the same as it depends on the implementation of the servlet container (Tomcat, Glassfish, ...) and the getSession() method might return just a wrapper instance.

So it is recommended to use a custom variable stored in the session to be used as locking object.

Here is my code proposal, feedback is welcome:

somewhere in a Helper Class, e.g. 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; } 

and then you can use it:

Object sessionLock = MyHelper.getSessionLock(getRequest(), null); synchronized (sessionLock) {   ... } 

Any comments on this solution?

like image 586
basZero Avatar asked Mar 21 '12 09:03

basZero


People also ask

What is the disadvantage of synchronization?

The main advantage of synchronization is that by using the synchronized keyword we can resolve the date inconsistency problem. But the main disadvantage of a synchronized keyword is it increases the waiting time of the thread and affects the performance of the system.

What are the risks of synchronization?

Synchronization risk arises from arbitrageur's uncertainty about when other arbitrageurs will start exploiting a common arbitrage opportunity (Abreu and Brunnermeier, 2002 and 2003). The arbitrage opportunity appears when prices move away from fundamental values.

When should synchronization be used?

Synchronization is needed when Object is mutable. If shared Object is immutable or all the threads which share the same Object are only reading the Object's state not modifying then you don't need to synchronize it. Java programming language provide two synchronization idioms: Methods synchronization.

Is synchronized method more efficient?

If you synchronize a code block within that method then more than one thread can execute the method simultaneously, but only one thread can enter the synchronized block at a time. From this we can conclude that synchronizing on the smallest possible code block required is the most efficient way to do it.


2 Answers

I found this nice explanation in spring-mvc JavaDoc for WebUtils.getSessionMutex():

In many cases, the HttpSession reference itself is a safe mutex as well, since it will always be the same object reference for the same active logical session. However, this is not guaranteed across different servlet containers; the only 100% safe way is a session mutex.

This method is used as a lock when synchronizeOnSession flag is set:

Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) {     return handleRequestInternal(request, response); } 

If you look at the implementation of getSessionMutex(), it actually uses some custom session attribute if present (under org.springframework.web.util.WebUtils.MUTEX key) or HttpSession instance if not:

Object mutex = session.getAttribute(SESSION_MUTEX_ATTRIBUTE); if (mutex == null) {     mutex = session; } return mutex; 

Back to plain servlet spec - to be 100% sure use custom session attribute rather than HttpSession object itself.

See also

  • http://www.theserverside.com/discussions/thread.tss?thread_id=42912
like image 71
Tomasz Nurkiewicz Avatar answered Sep 18 '22 18:09

Tomasz Nurkiewicz


In general, don't rely on HttpServletRequest.getSession() returning same object. It's easy for servlet filters to create a wrapper around session for whatever reason. Your code will only see this wrapper, and it will be different object on each request. Put some shared lock into the session itself. (Too bad there is no putIfAbsent though).

like image 28
Peter Štibraný Avatar answered Sep 22 '22 18:09

Peter Štibraný