How can ThreadLocal cause a memory leak in web servers, and how do you prevent it?
Web servers typically run requests on a pooled set of worker threads that are reused across many different incoming requests. If a servlet or filter sets a value into a ThreadLocal during one request but never calls remove() on it, that value stays attached to the thread's internal ThreadLocalMap indefinitely, and the very next request that happens to land on that same pooled thread will silently see the leftover context from the previous, completely unrelated request -- a serious security concern in something like a multi-tenant system. It gets worse if the leaked value references an object loaded by a web application's own class loader, such as a Hibernate entity: because the ThreadLocalMap entry keeps that object reachable, the entire class loader for that web application can never be garbage collected, even after the application is redeployed, resulting in a slow but permanent memory leak that eventually exhausts Metaspace. The fix is straightforward -- always call threadLocal.remove() inside a finally block, typically implemented as a servlet Filter wrapping the request in a try/finally that guarantees cleanup runs no matter how the request handling exits.
Ready to master this question?
Generate a complete walkthrough — background, the full answer in plain language, a working code example explained line by line, a real-world scenario, common mistakes, and how this same question gets asked in different ways.
Sign in to generate a response