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