Spring SecurityContextHolder uses a ThreadLocal to store the SecurityContext which is local to the thread and it cannot be accessed or modified by other thread.
But in the spring documentation, it is suggesting to set/create new security context instead of using SecurityContextHolder.getContext().setAuthentication(authentication) as it may lead to race conditions.
I'm not getting on how does race condition even occur when SecurityContext is local to the thread. Even if there are multiple threads being executed simultaneously, i don't see any race condition happening.
Please let me know why it is even mentioned in the doc?
https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#:~:text=We%20start%20by%20creating%20an%20empty%20SecurityContext.%20You%20should%20create%20a%20new%20SecurityContext%20instance%20instead%20of%20using%20SecurityContextHolder.getContext().setAuthentication(authentication)%20to%20avoid%20race%20conditions%20across%20multiple%20threads.
Related
As we know Tomcat has approx 200 threads and Jetty has some default count threads in their respective thread pools. So if we set something in a ThreadLocal per request, will it be there in the thread for life time or will Tomcat clear the ThreadLocal after each request.
If we set something in userContext in a filter do we need to clear it every time the filter exits?
Or will the web server create a new thread every time, if we don't have a thread pool configuration?
public static final ThreadLocal<UserContextDto> userContext = new ThreadLocal<>();
Yes, you need to clear ThreadLocal. Tomcat won't clear ThreadLocals.
No, new thread is not created every time. A thread from the pool is used to serve a request, and returned back to pool once request is complete.
This not only applies to Tomcat, it applies to Jetty and Undertow as well. Thread creation for every request is expensive in terms of both resources and time.
No, Tomcat will not clear ThreadLocals that your code creates, which means they will remain and could pollute subsequent requests.
So whenever you create one, make sure you clear it out before that same request or whatever exits.
It should also be noted that subsequent requests - even using the identical URL - could well be executed in a totally different thread, so ThreadLocals are not a mechanism for saving state between requests. For this, something like SessionBeans could be used.
If you put something in a ThreadLocal in a Thread that is not 100% under your control (i.e. one in which you are invoked from other code, like for a HTTP request), you need to clear whatever you set before you leave your code.
A try/finally structure is a good way to do that.
A threadpool can't do it for you, because the Java API does not provide a way to clear a thread's ThreadLocal variables. (Which is arguably a shortcoming in the Java API)
Not doing so risks a memory leak, although it's bounded by the size of the thread pool if you have one.
Once the same thread gets assigned again to the code that knows about the ThreadLocal, you'll see the old value from the previous request if you didn't remove it. It's not good to depend on that. It could lead to hard to trace bugs, security holes, etc.
I'm trying to cache values in a ConcurrentHashMap in the Session. In order to avoid race conditions and ensure that my map is created before any threads attempt to use it, I use HttpSessionListener.sessionCreated() to add the map to the Session:
#Override
public void sessionCreated(HttpSessionEvent event) {
event.getSession()
.setAttribute(MY_CACHE_KEY, new ConcurrentHashMap());
}
Is this code guaranteed to complete before any other threads access the session (via request.getSession() for example)?
I looked at the HttpSessionListener JavaDoc and the Servlet 4.0 Spec. and there don't seem to be any guarantees about thread safety.
The Serlvet Spec. references session thread-safety a few times, but none of these references related to session listeners and session creation as I understand them:
7.7.1 Threading Issues
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 thread safe manner. The Developer has the responsibility for thread safe 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. Unless explicitly stated elsewhere in the specification (for example Section 7.7.1, “Threading Issues” on page 7-67 for session objects), objects vended from the request or response must be assumed to be non thread safe. This includes, but is not limited to the PrintWriter returned from
ServletResponse.getWriter() and the OutputStream returned from ServletResponse.getOutputStream().
11.5 Listener Instances and Threading
The container is required to complete instantiation of the listener classes in a Web application prior to the start of execution of the first request into the application. The container must maintain a reference to each listener instance until the last request is serviced for the Web application.
Attribute changes to ServletContext and HttpSession objects may occur concurrently. The container is not required to synchronize the resulting notifications to attribute listener classes. Listener classes that maintain state are responsible for the integrity of the data and should handle this case explicitly.
It seems obvious that sessionCreated() must complete before threads have access to the session, but "obviously correct code" has been unsafe for multithreading before.
This ambiguity doesn't exist for ServletContextLister.contextInitialized() since it is guaranteed to complete before Servlet initialization and Servlet.init() is guaranteed to be single-threaded and occur before any requests.
I've tested Tomcat at least and it does ensure that sessionCreated() completes before request.getSession() returns. I tested by putting a breakpoint in sessionCreated() and sending a request which called request.getSession(). This request didn't complete until I continued from the breakpoint. However, one Servlet container implementation's behavior isn't really conclusive proof that all containers/servers behave this way.
I am working on implementing a very specific health check strategy for my service. Here are the details :
All the application threads update a mutable Spring bean "problemDetectedTimestamp" when they come across a problem.
I have a background thread(implemented using ScheduledExecutorService) running every second which updates another mutable Spring bean "isServiceHealthy" based on the value of "problemDetectedTimestamp". To elaborate, the background thread checks whether the value of "problemDetectedTimestamp" falls in the last thread execution interval. If yes, the "isServiceHealthy" flag is updated to "false". I have some other application logic which is dependent on "isServiceHealthy" flag.
Now, we have multiple threads running and as such, I would want the "problemDetectedTimestamp" to be updated in a thread safe manner without incurring the overhead of using "synchronized" blocks. I am considering declaring "problemDetectedTimestamp" as a volatile variable to ensure that writes from application threads are atomic and my background thread reads it from memory rather than from its local cache. But, I am not sure of how to declare the bean as "volatile" in Spring XML as "volatile" is a concept specific to java/c++ and I am pretty sure Spring is not tighly coupled with java as such.
I've been exposing beans in our Spring web applications in case we need to make configuration changes on the fly. Recently I've been reviewing concurrency and I started to wonder what happens in other threads when you mutate one of these beans through JMX?
Does JMX have some way of forcing a memory model refresh so you don't need to worry about making the field volatile/synchronized to ensure other threads see the change?
When Tomcat creates a new thread to handle a request, that thread will see the changes even if the field is not thread-safe, correct? So unless I need the change to immediately take effect in current request threads is there any reason to worry about concurrency issues?
The JMX handler is not a special thread. Any changes there that need to be seen in other threads will need to be marked as volatile or synchronized.
// this needs to be volatile because another thread is accessing it
private volatile boolean shutdown;
...
#JmxOperation(description = "Shutdown the server")
public void shutdownSystem() {
// this is set by the JMX connection thread
shutdown = true;
}
That said, typically JMX values are statistics or configuration settings that I don't mind being lazily updated when the next memory barrier is crossed. This applies to counters and other debug information as well as booleans and other values that are only set by the JMX although they are used by other threads. In those cases, I do not mark the fields as volatile and it hasn't bitten us yet. YMMV.
FYI, the #JmxOperation annotation is from my SimpleJmx library.
I am running into a situation where I use ThreadLocal static variable to hold a bean that contains various metrics values from different classes during the lifecycle of the request. In a filter I create the bean and set it in a thread local variable and remove it from the thread local variable in the same filter after request has been processed. What I am running into is that the bean containing values from other requests! The only explanation for this is the thread being shared to process multiple requests at the same time. So the question in the title.
While one thread will generally process a single request (speaking about tomcat, for sure), the thread may process multiple requests over time but not w/o finishing the existing request, unless using include/forward alikes.
I'd VERY strognly recommend you to use attribute (setAttribute()) of the said request w/ your bean and use it for profiling. If you can't provide the request to various methods... well you are stuck w/ the ThreadLocal [which is not so bad solution].
Alternatively you can post the code how you install/remove the threadLocal bean.
Keep in mind that you have to to some managing the of that bean as well (it will not be available outside the request).
Edit: forgot to ask: do you use try/finally calling doFilter(...)?
the code should be like that
installBean();
try{
chain.doFilter(req, resp);
}finally{
Bean b = deinstallBean();
useTheMetrics(b);
//potentially, process exception, etc
}
It could also be that your filter is not always called in the sequence you expect it to be. Threads are reused to process multiple requests one after another, so if the removal of the value in the ThreadLocal does not happen, it will still be there when the thread processes its next request.
Yes, you can assume that a single thread will process each request.
Use a finally block to clear (set to null) the ThreadLocal in the filter after processing the rest of the chain. That will prevent data from previous requests from being mingled with the current request.