HttpSessionimplementations: developers tend to forget that multiple threads can concurrently access objects on the session. From my experience, web developers think even less about session concurrency than security (yes, it's possible).
It's terribly easy to focus on the happy path during development and ignore the edge cases (especially considering how difficult it is to test them). In the past, we web developers only had to worry about users who double clicked links and buttons, but now technologies like AJAX and asynchronous session replication have exacerbated the problem by increasing the likelihood of two threads stepping on each other and resulting in race conditions or deadlocks.
Case in point: I once had a server grind to a halt due to a strange deadlock. The stack dump showed that one thread was waiting for a lock held by another thread which seemed to be mysteriously stuck in
daemon runnable at java.lang.Object.hashCode(Native Method) at java.util.HashMap$Entry.hashCode(Unknown Source) at java.util.AbstractMap.hashCode(Unknown Source) ...
How on Earth could a thread block in
Object.hashCode()? The call to a non-synchronized
HashMap in the stack trace unlocked the mystery. Someone nested a
HashMap instance deeply within the session. While one request iterated over the map, another request came in and mutated the map which created a cycle in the
HashMap's underlying data structure, and the first thread went into an infinite loop.
Object.hashCode() didn't really block, but the loop was so tight, it sure looked that way.
How do you avoid this pitfall? There is no silver bullet. You could synchronize. Synchronizing at the appropriate level is tricky. Too fine grained, you don't really solve the problem. Too coarse, and a long running request can block subsequent requests. Last I checked, Struts Action 1 performed no synchronization on session scoped beans, and it wasn't a problem you could solve at the application level (i.e. how would you get Struts to acquire your lock before mapping request parameters to your session-scoped bean?). I'm not sure how JSF implementations and Spring WebFlow address this problem, but I'd love to hear. My current project manages concurrency quite successfully using an in-house wizard framework.
You could also serialize the session at the beginning and end of each request (each request would have its own copy of the session). I think Rails takes this approach by virute of the fact that each request executes in its own process. I'm not sure how you would handle concurrent requests though; would the second request overwrite the session changes from the first? Does Rails write the problem off as too rare to worry about? I suppose you could mitigate this problem to some degree by storing the session in a hidden field on the client.
Nowadays I think I favor keeping all your state in the database and using one of the aforementioned clustered caching frameworks to scale. Thoughts?