It appears that when a thread (T1) executing the servlet's doGet() method calls setAttribute() on the instance of HttpSession implementation (S1), it locks on the monitor of S1. While holding that lock it goes into the iteration of allSessions inside the listener's attributeAdded() method and calls getAttribute(). It looks like inside getAttribute(), WebSphere locks on that instance's monitor (possibly because it is setting a lastUpdateTime field?). So, T1 will in turn lock the monitors of S1, S2, S3, S4, S5... all the while holding the lock on S1 from the setAttribute() call in the servlet.

So if at the same time another thread (T2) is locking on another session (S2)'s monitor in the servlet and then goes into the loop in addAttribute(), the threads deadlock on the S1 and S2 monitors.

I have been unable to find anything explicit in the J2EE specs about this but this part of the Servlet 2.4 spec implies that the container should not be synchronizing on instances of HttpSession implementations:

SRV.7.7.1 Threading Issues

Multiple servlets executing request threads may have active access to
a single session object at the same time. The Developer has the
responsibility for synchronizing access to session resources as
appropriate.

JBoss does not show any deadlocks when we run the test against it. So my questions are:

Is my understanding correct?

If so, is this a bug or contravention of the J2EE spec in WebSphere?

If not, and it is valid behaviour that the developer should know about and code around, is this behaviour documented anywhere?

2 Answers
2

The Servlet 2.5 MR6 contains a clarification to the part of the Servlet spec quoted in the question:

Clarify SRV 7.7.1 "Threading Issues" (Issue 33)

Change the paragraph which currently is

"Multiple servlets executing request threads may
have active access to a single session object at the same time. The
Developer has the responsibility for synchronizing access to session
resources as appropriate."

to read

"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 still current in Servlet 3.0 MR1 and makes WAS's behaviour look more reasonable. However, I would take from it that *set*Attribute might be synchronized but it not that *get*Attribute would be.

So I think the answer is:

WAS is complying with the Servlet spec according to the clarification in 2.5 MR6

The spec leaves room for misunderstanding

WAS is more zealous with its synchronization than would reasonably be expected from the spec and AFAIK this behaviour is not clearly documented anywhere

(As a side note, changing the test case so that listener.attributeAdded() calls setAttribute instead of getAttribute doesn't cause deadlocks on JBoss 4 or 5.)

You have probably found a not supported use case of HttpSession in IBM WebSphere specific implementation. Why not report it to IBM ?

A point you have missed for your implementation: the JavaEE container may passivate HttpSession objects (by serializing it on disk or database) to free memory if the server has to handle too many sessions under load. Your listener prevents the garbage collector to free that sessions.

By the way, the HttpSession object is supposed to be only used by the thread that corresponds to its own session. As you found in specification, in case of multiple concurrent threads from the same session, the code must use synchronization mechanism on the HttpSession objet.

Session listeners are event-based with all necessary information in event, such a design is enough to avoid the listener to keep all references to living HttpSession objects the way you do.

Quering from one thread all living sessions in the container is strange and unexpected. It is not the job of a web application but of a monitoring or auditing tool. In that case, other means like JMX query or PMI interface in the specific WebSphere context should be used.

To help you, here is an alternate implementation of your listener to achieve the same session attribute count but without keeping any reference on HttpSession. Beware: it was neither compiled nor tested.

Thanks Yves. Is "the HttpSession object is supposed to be only used by the thread that corresponds to its own session" a guideline or rule or best practice?
–
Paul MedcraftJan 27 '12 at 18:23

I would say it is the standard use case that rules the HttpSession implementation from the JavaEE container vendors' point of view. Any other use case is only relevant for internal container tools or monitoring/auditing tools. By the way, you still have the limitation to access passivated sessions without container specific implementation details.
–
Yves MartinJan 30 '12 at 9:24