3

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.

stiemannkj1
  • 4,418
  • 3
  • 25
  • 45
  • 2
    This question ([Is sessionCreated() from a HttpSessionListener automatically synchronized with request.getSession()?](https://stackoverflow.com/q/42051883/2985643) ) is similar to yours, though it does not help you at all since nobody answered it! – skomisa Nov 08 '18 at 00:31
  • 1
    Like you, I couldn't find anything explicit on this in the Servlet 4.0 spec. However, [this SO question](https://stackoverflow.com/q/9802165/2985643) raised an interesting issue related to your question: _"Is it guaranteed that the session object is the same instance for all threads processing requests from the same user?"_. The accepted answer refers to the Javadoc for the Spring method [WebUtils.getSessionMutex](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/WebUtils.html#getSessionMutex-javax.servlet.http.HttpSession-)... – skomisa Nov 17 '18 at 06:33
  • 1
    ...which states: _"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**."_. Of course this is not relevant or helpful for your question if your app server only runs a single JVM, but otherwise it seems that you may need a mutex anyway, which could also resolve your concern. (While I am quoting a Spring method, the issue is obviously relevant even if you are not using Spring.) – skomisa Nov 17 '18 at 06:36

0 Answers0