On 17/01/18 17:05, Christopher Schultz wrote:
> All,
> 
> I have a use-case related to caching where I need to make sure that an
> operation only happens one time with respect to an object in the
> session. Basically, I want to build a cache and put it into the
> session, but it needs to be thread-safe enough that two threads can't
> see the object isn't there, build such an object, and then put it into
> the session (thereby overwriting each other).
> 
> This is not a theoretical problem... we are observing threads
> overwriting each other's caches in the session.
> 
> The good news is that I only have to deal with a single container
> instance on a single server/JVM, so there is no concern about session
> replication or anything else like that. I also don't have to worry
> about the session being created/destroyed around the same time.
> 
> The servlet API says that HttpServletRequest.getSession() returns an
> HttpSession object (well, an object implementing HttpSession), but
> makes no guarantees about its thread-safety (e.g. with respect to
> getAttribute/setAttribute calls), so I cannot guarantee anything about
> whether getAttribute/setAttribute calls will be safe, though they
> would really have to be otherwise the server would encounter all kinds
> of problems.

[get|set]Attribute operate on a ConcurrentHashMap so they are
thread-safe but you still need to co-ordinate if multiple threads are
trying to write.

> That doesn't really matter because I need to do something like this:
> 
> Cache myCache = null;
> synchronized (something) {
>   myCache = session.getAttribute("cacheKey");
>   if(null == myCache) {
>     myCache = new Cache();
>     session.setAttribute("cacheKey", cache);
>   }
> }
> 
> If I don't synchronize on a consistent monitor, there is a race
> condition between the "get" and the "set" between threads using the
> session.
> 
> So the question is "what should I use as the monitor?"
> 
> My first thought was that I should use the session object itself:
> 
> Cache myCache = null;
> synchronized (session) {
>   myCache = session.getAttribute("cacheKey");
>   if(null == myCache) {
>     myCache = new Cache();
>     session.setAttribute("cacheKey", cache);
>   }
> }
> 
> That would be the best option, since it's the object I actually care
> about. However, I believe Tomcat sometimes (always) provides wrapper
> objects around servlet-spec-defined objects and I'm wondering if there
> are any guarantees about the HttpSession object being consistent
> across threads?
> 
> That is, will Tomcat always give an identical object to two different
> threads whose requests are associated with the same session? Or are
> there cases where the two threads might get different objects?

It should always be the same object. Looking at the code, I don't see
any obvious holes.

For the record, relevant code includes:
o.a.catalina.connector.Request.getSession()
o.a.catalina.session.ManagerBase.createSession(String)
o.a.catalina.session.StandardSession.getSession()

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to