Using request.getSession () as a lock object?

I have java code that receives and sets a session attribute:

Object obj = session.getAttribute(TEST_ATTR); if (obj==null) { obj = new MyObject(); session.setAttribute(obj); } 

To make this code thread safe, I would like to wrap it in a synchronized block. But what am I using as a lock object? Does it make sense to use a session?

 synchronized (session) { Object obj = session.getAttribute(TEST_ATTR); if (obj==null) { obj = new MyObject(); session.setAttribute(obj); } } 
+10
java concurrency thread-safety locking session
Nov 30 '09 at 15:50
source share
7 answers

It is generally not recommended to use a lock that you do not control. The lock should be limited as much as possible, and since the session is more or less global, it does not fit the bill. Try using a separate lock from the java.util.concurrent.locks package and combine it into your class.

+3
Nov 30 '09 at 16:05
source share

In the context of servlets? Servlets can be distributed among several processes, so you cannot always have the same session object. The consequence of this is that the servlet container may decide to provide you with another session object in the same process.

IIRC, Brian Goetz wrote an interesting article about the difficulties of doing things right with sessions.

My advice: avoid sessions as much as possible and don't block random objects (use a blocking object that has no other purpose).

+3
Nov 30 '09 at 16:08
source share

I looked at the article you published. You can skip synchronization all together and take the same approach that the author took using the comparison and setup command to ensure that your data is correct:

 ServletContext ctx = getServletConfig().getServletContext(); AtomicReference<TYPE> holder = (AtomicReference<TYPE>) ctx.getAttribute(TEST_ATTR); while (true) { TYPE oldVal = holder.get(); TYPE newVal = computeNewVal(oldVal); if (holder.compareAndSet(oldVal, newVal)) break; } 

holder.compareAndSet (old, new) will return false if any other thread has updated the holder value since it was last read. holder.compareAndSet (,) is placed in a while (true) loop, so if the value has changed before you could write it, you will get the opportunity to read the value again and try to write again.

http://java.sun.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicReference.html

+3
Nov 30 '09 at 16:36
source share

The specification does not guarantee that this will generally help:

 synchronized (session) { Object obj = session.getAttribute(TEST_ATTR); if (obj==null) { obj = new MyObject(); session.setAttribute(obj); } } 

(It may work for specific implementations, but there is no guarantee that it will work in all containers.)

Servlet 2.5 MR6 says:

Several servlets that execute request flows can have active access to the same session object at the same time. The container must ensure that the manipulation of internal data structures representing session attributes is performed in thread safe mode. The developer is responsible for the threaded access to the attribute objects themselves. This protects the collection of attributes within the HttpSession object from simultaneous access, eliminating the possibility of the application to make this collection corrupt.

Basically, the specification makes your problem. Your solution should be tailored to your design and deployment plan. I am not sure that there is a global solution to the problem that will work in all cases; however, you can get a more effective answer if you are more specifically about the architecture of your application and the configuration of your application server.

+2
Nov 30 '09 at 16:42
source share

Your code will not work for at least two reasons.

1) If the session does not exist, you can easily create it twice for the same user and have an ugly race condition.

2) If the session is not the same object in streams, it will not work in any case. The session will probably be equals() for the same session in a different thread, but this will not work.

+1
Nov 30 '09 at 16:06
source share

You do not need to block because session.setAttribute() is thread safe (see @McDowell's servlet specification comment above).

However, use another example. Say you would like to reread the attribute value and then update it if <= 100. In this case, you will need to synchronize the code block for getAttribute() compare <= 100 and setAttribute() .

Now what should you use to block? Remember that synchronization does not occur if different objects are used for locking. Therefore, different code blocks must use the same object. Your choice of session object can be wonderful. Remember also that different code blocks can access the session (both read and write), even if you made a lock, if this other code also does not block the session object. The catch here is that too many places in your code block the session object and therefore must wait. For example, if your code block uses session attribute A and another piece of code uses session attribute B, it would be nice if they did not need to wait from each other, making a lock on the session object. Using static objects named LockForA and LockForB might be the best choice for using your code β€” for example, synchronized (LockForA) { }.

+1
Nov 10 2018-11-11T00:
source share

I had the same problem and didn’t want to use it for my class, because creating my object could take second and stop flows from other sessions where the object was already created. I did not want to use the request session object for synchronization, because the application server implementation can return a different session facade to different requests, and synchronization on different objects simply does not work. So I decided to put the object in the session as a lock and use the double check idiom to ensure that the lock is only created once. Syncing in the MyObject area is no longer a problem because creating an object is pretty fast.

 Object lock = session.getAttribute("SessionLock"); if (lock == null) { synchronized (MyObject.class) { lock = session.getAttribute("SessionLock"); if(lock == null) { lock = new Object(); session.setAttribute("SessionLock", lock); } } } synchronized (lock) { Object obj = session.getAttribute(TEST_ATTR); if (obj==null) { obj = new MyObject(); session.setAttribute(obj); } } 
0
Jun 27 '13 at 13:04 on
source share



All Articles