Also, does the object that is being set have to be thread safe in order to guarantee that we know what the state of the object stored in session is known.
Also, I was reading on the web that some suggest using:
synchronized(session) {
session.setAttribute("abc", "abc");
}
Is this a valid suggestion?
Servlet 2.5 spec:
Multiple servlets executing request
threads may have active access to the
same session object at the same time.
The container must ensure that
manipulation of internal data
structures representing the session
attributes is performed in a
threadsafe manner. The Developer has
the responsibility for threadsafe
access to the attribute objects
themselves. This will protect the
attribute collection inside the
HttpSession object from concurrent
access, eliminating the opportunity
for an application to cause that
collection to become corrupted.
This is safe:
// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);
This is not safe:
HttpSession session = request.getSession();
Integer n = (Integer) session.getAttribute("foo");
// not thread safe
// another thread might be have got stale value between get and set
session.setAttribute("foo", (n == null) ? 1 : n + 1);
This is not guaranteed to be safe:
// no guarantee that same instance will be returned,
// nor that session will lock on "this"
HttpSession session = request.getSession();
synchronized (session) {
Integer n = (Integer) session.getAttribute("foo");
session.setAttribute("foo", (n == null) ? 1 : n + 1);
}
I have seen this last approach advocated (including in J2EE books), but it is not guaranteed to work by the Servlet specification. You could use the session ID to create a mutex, but there must be a better approach.
No. And since you don't want the same client (with session) to be doing concurrent requests, you should serialize these requests like the AbstractController does in Spring MVC
In some ways, this depends on your client design.
Do you have the opportunity, in your web design, for a single client to have multiple outstanding simultaneous requests using the same HTTP session? This seems difficult to do unless you tie a single HTTP session to multiple sockets. (aka, AJAX) Short of doing this, a given client's HTTP access will be single-threaded as far as the server is concerned, which means a single session is effectively Thread safe.
Synchronization of your session objects will make the application safer against future changes that make your web application capable of having multiple simultaneous requests, so it's not a bad idea. In modern Java implementations, synchronization does not have the large cost that was previously associated with it, especially when the synchronization is usually uncontended. If your application uses AJAX, which implies that you expect multiple in-flight simultaneous requests to your web server, then synchronization is a must.
They are not, but most of the times, your clients will only access them with a single thread.
Different clients will have different threads and each one will have its own Session.
As Eddie points out, one situation where you may face two thread accessing the same session is two ajax calls are attempting to modify the same session attribute. Otherwise you won't have problems.
The session is not thread safe and neither the get not the set methods are guaranteed to be thread safe. In general in a servlet container you should assume to be in a multi threaded environment and no provided tooling is safe.
This also goes for the objects you store in the session. The session itself will not manipulate the stored object but you can retrieve the object in different thread and attempt to manipulate it. It is up to you to examine your own code to see if race conditions are possible.
The code example you posted is valid, but the problem may exist beyond the limited scope of your example. It assures there are no conditions while setting to the session, but there is nothing preventing an other thread to override the set. If the code in your request depends of the value remaining unchanged you could still be in trouble.
Related
I'm trying to cache values in a ConcurrentHashMap in the Session. In order to avoid race conditions and ensure that my map is created before any threads attempt to use it, I use HttpSessionListener.sessionCreated() to add the map to the Session:
#Override
public void sessionCreated(HttpSessionEvent event) {
event.getSession()
.setAttribute(MY_CACHE_KEY, new ConcurrentHashMap());
}
Is this code guaranteed to complete before any other threads access the session (via request.getSession() for example)?
I looked at the HttpSessionListener JavaDoc and the Servlet 4.0 Spec. and there don't seem to be any guarantees about thread safety.
The Serlvet Spec. references session thread-safety a few times, but none of these references related to session listeners and session creation as I understand them:
7.7.1 Threading Issues
Multiple servlets executing request threads may have active access to the same session object at the same time. The container must ensure that manipulation of internal data structures representing the session attributes
is performed in a thread safe manner. The Developer has the responsibility for thread safe access to the attribute objects themselves. This will protect the attribute collection inside the HttpSession object from concurrent access,
eliminating the opportunity for an application to cause that collection to become corrupted. Unless explicitly stated elsewhere in the specification (for example Section 7.7.1, “Threading Issues” on page 7-67 for session objects), objects vended from the request or response must be assumed to be non thread safe. This includes, but is not limited to the PrintWriter returned from
ServletResponse.getWriter() and the OutputStream returned from ServletResponse.getOutputStream().
11.5 Listener Instances and Threading
The container is required to complete instantiation of the listener classes in a Web application prior to the start of execution of the first request into the application. The container must maintain a reference to each listener instance until the last request is serviced for the Web application.
Attribute changes to ServletContext and HttpSession objects may occur concurrently. The container is not required to synchronize the resulting notifications to attribute listener classes. Listener classes that maintain state are responsible for the integrity of the data and should handle this case explicitly.
It seems obvious that sessionCreated() must complete before threads have access to the session, but "obviously correct code" has been unsafe for multithreading before.
This ambiguity doesn't exist for ServletContextLister.contextInitialized() since it is guaranteed to complete before Servlet initialization and Servlet.init() is guaranteed to be single-threaded and occur before any requests.
I've tested Tomcat at least and it does ensure that sessionCreated() completes before request.getSession() returns. I tested by putting a breakpoint in sessionCreated() and sending a request which called request.getSession(). This request didn't complete until I continued from the breakpoint. However, one Servlet container implementation's behavior isn't really conclusive proof that all containers/servers behave this way.
I've sent the same request to a Spring MVC project with two browsers, but I got the same threadlocal, so the instances in threadlocal are the same.,Why?
Threadlocal is bound to a thread / process, not to a session. JVM does not really know or care about the concept of web sessions, that's a higher level of abstraction.
It is well possible that two web requests with two sessions are handled by the same thread. Most servers use a pool of threads that they reuse rather than create a new thread for each request or even session. If the processing of the first request leaves something in the threadlocal after it's done processing the request, well, that's what the next request will find there.
Store the data you need to keep per-session in HttpServletRequest.getSession() instead.
I have 2 servers.
Server A has a cron system, which given a trigger requirement, calls the Server B through a servlet
In server B, when receiving the server A's call, i store serveral informations on the HttpSession and then i start a new thread, so i could free server A.
I have found, thought logs, that in several cases, when the thread in Server B is reaching the HttpSession, the values that were set before are different. They are not null or blank, they have acctual values, but not the ones i put.
The server A fires like, 30 notifications each 5 minutes. This means i will have several concurrent threads.
Why is the HttpSession being overriden by another thread?
Section 2.3.3.4 of the Servlet Specification v 3.0 says,
If a thread created by the application uses the container-managed
objects, such as the request or response [or session] object, those objects
must be accessed only within the object’s life cycle [...].
HttpSession objects are certainly container-managed objects, but their life cycle is not clearly defined by the Servlet specification. It seems plausible, however, to consider the life cycle to end when the session has been invalidated, whether explicitly or by time out, and no request belonging to that session is being serviced. After that point, if you continue to access the session object then all bets are off. In particular, the container is permitted to cache and re-use managed objects, including session objects.
If your server A does not participate in session tracking, then every request will be assigned to a new session, and each one's lifetime will be a single timeout period. In this case, you could consider setting the [default] timeout long enough to ensure that sessions do not time out during the course of one computation (but see below). If your server A does participate in session tracking, on the other hand, then the session object will be open for modification on each request.
Whether server A participates in session tracking or not, however, it is poor form for an application thread such as those you start manually to access container-managed objects. It would be better all around to use a different mechanism to provide data to them.
If multiple requests are handled by a server to run a single servlet then where we need to take care of synchronization?
I have got the answer from How does a single servlet handle multiple requests from client side how multiple requests are handled. But then again there is a question that why we need synchronization if all requests are handled separately?
Can you give some real life example how a shared state works and how a servlet can be dependent? I am not much interested in code but looking for explanation with example of any portal application? Like if there is any login page how it is accessed by n number of users concurrently.
If more than one request is handled by the server.. like what I read is server make a thread pool of n threads to serve the requests and I guess each thread will have their own set of parameters to maintain the session... so is there any chance that two or more threads (means two or more requests) can collide with each other?
Synchronization is required when multiple threads are modifying a shared resources.
So, when all your servlets are independent of each other, you don't worry about the fact that they run in parallel.
But, if they work on "shared state" somehow (for example by reading/writing values into some sort of centralized data store); then you have to make sure that things don't go wrong. Of course: the layer/form how to provide the necessary synchronization to your application depends on your exact setup.
Yes, my answer is pretty generic; but so is your question.
Synchronization in Java will only be needed if shared object is mutable. if your shared object is either read-only or immutable object, then you don't need synchronization, despite running multiple threads. Same is true with what threads are doing with an object if all the threads are only reading value then you don't require synchronization in Java.
Read more
Basically if your servlet application is multi-threaded, then data associated with servlet will not be thread safe. The common example given in many text books are things like a hit counter, stored as a private variable:
e.g
public class YourServlet implements Servlet {
private int counter;
public void service(ServletRequest req, ServletResponse, res) {
//this is not thread safe
counter ++;
}
}
This is because the service method and Servlet is operated on by multiple thread incoming as HTTP requests. The unary increment operator has to firstly read the current value, add one and the write the value back. Another thread doing the same operation concurrently, may increment the value after the first thread has read the value, but before it is written back, thus resulting in a lost write.
So in this case you should use synchronisation, or even better, the AtomicInteger class included as part of Java Concurrency from 1.5 onwards.
I know that every request is served by a servlet thread, but will it be possible for one user session, two request served by two different thread?
If the situation above really happens, what about thread local variable stored by first request-serving thread be read by second request-serving thread?
I'm afraid that if I store user credential in Spring Security's SecurityContextHolder(which uses thread local variable) in first thread, the second thread will not be able to access the user credential...
I know that every request is served by a servlet thread, but will it be possible for one user session, two request served by two different thread?
Yes, that's possible.
I'm afraid that if I store user credential in Spring Security's SecurityContextHolder(which uses thread local variable) in first thread, the second thread will not be able to access the user credential...
Security is established separately for each request by Spring, you do not have to handle this yourself.
No, one request will not be served by several threads. What can really happen is serving of 2 requests by one thread. This is the reason that you should be very careful using thread local variables yourself. However you can trust Spring framework: it does things right. It can for example use session or request ID when using thread local, so 2 request being processed by one thread will not be confused.
Two separate requests of the same user are handled (most likely) by two different threads.
I am not sure what Spring does, but the Servlet api provides a way to retrieve data that is specific to the user session (how the server tracks the session is irrelevant, but have a look at cookies and url rewriting).
Now, If I wanted to have the user credentials on a threadlocal variable (which is not unusual, as the ThreadLocal pseudo-singleton is the most convenient way of injection I know), I would store them on the users HttpSession (which is persistent across all requests of the same user) and use a servlet filter to put them on the threadlocal at the beginning of each request.
I hope this makes things a bit clearer for you. I find it is better to know what's happening under the hood even when using the most up to date framework :)