Reputation: 705
I have the following request context class that is used to collect certain information for future processing in Servlet filter:
public class ApplicationRequestContext {
private static final ThreadLocal<AppRequest> tl = new ThreadLocal<AppRequest>();
public static void begin(HttpServletRequest httpRequest) {
tl.set(getAppRequest(httpRequest));
}
public static void finish() {
tl.remove();
}
}
getAppRequest(httpRequest)
just returns an object. And in the Servlet filter...
public class ApplicationServletFilter implements javax.servlet.Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
ApplicationRequestContext.begin(httpRequest);
/* other stuff */
chain.doFilter(httpRequest, httpResponse);
} catch (Exception e) { /* … */ }
finally {
ApplicationRequestContext.finish();
}
}
}
I would like to know, could this setup have multiple incoming requests to possibly overwrite each others' data (getAppRequest(httpRequest)
object obviously is going to be unique)? Is this even thread-safe?
Upvotes: 0
Views: 132
Reputation: 1621
You have to remember, each Thread
has its own ThreadLocal
-- actually, to be precise, its own ThreadLocal.ThreadLocalMap
(I'm using OpenJDK as a sample).
When your ThreadLocal
, named tl
, calls on its set()
method, it basically creates a new ThreadLocalMap
and have tl
as a reference as a key to create a ThreadLocalMap.Entry
.
Since each Servlet request uses a unique thread (either from a managed thread pool or spawning a new one, and the fact that no two Servlet threads process the same request), then tl.set()
have that ThreadLocal
's newly created ThreadLocalMap
as a reference to that Servlet Thread
's ThreadLocal.ThreadLocalMap
.
Now, when tl.get()
is called, we simply get the Servlet Thread
's ThreadLocalMap
, and do a lookup with ThreadLocalMap.getEntry()
, to fetch the value we have put in, e.g. getAppRequest(httpRequest)
.
The main point to remember here is, yes, you are using a single ThreadLocal
object, named tl
, but each Thread
, in this case, a thread that the Servlet container uses to process each request, including its filter(s), is going to have its own ThreadLocal.ThreadLocalMap
with a [weak] reference of this ThreadLocal
object as its key.
So, t1
is just a key in a table of ThreadLocal.ThreadLocalMap.Entry
(tl.ThreadLocalMap.Entry
) to fetch Thread
's LocalThread.ThreadLocalMap
which is unique to that thread alone. Therefore, it is thread-safe, and those begin()
and finish()
calls are basically putting data in each Thread
's.
Upvotes: 1
Reputation: 139
Yes, it's thread-safe. And, It could not overwrite each others' data.
Because,
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html
Upvotes: 1