multithreading
How does ThreadLocal work and where is it used in real projects?
What is ThreadLocal?
ThreadLocal provides thread-confined variables — each thread accessing the variable gets its own, independently initialized copy. No synchronization is needed because threads never share the value.
ThreadLocal<String> userContext = new ThreadLocal<>(); // Thread A userContext.set("user-akash"); System.out.println(userContext.get()); // "user-akash" // Thread B — completely independent userContext.set("user-rahul"); System.out.println(userContext.get()); // "user-rahul"
How Does It Work Internally?
- Each
Threadobject has a hidden field:Thread.threadLocals(aThreadLocalMap). - When you call
threadLocal.set(value), it stores the value inside the current thread's own map, keyed by theThreadLocalinstance. get()retrieves from the current thread's map — zero contention, zero locking.
Real-World Usage
| Framework | Use Case |
|---|---|
| Spring Security | SecurityContextHolder stores the authenticated user per request thread |
| Hibernate | Session-per-request pattern — Session bound to current thread |
| SLF4J / Log4j MDC | MDC.put("requestId", id) — correlates logs across a single request |
| Transaction Management | JDBC Connection bound to thread via DataSourceUtils |
| SimpleDateFormat | Non-thread-safe formatter wrapped in ThreadLocal for reuse |
⚠️ Memory Leak Pitfall
In thread pools (e.g., Tomcat, ExecutorService), threads are reused. If you don't call threadLocal.remove() after each task:
- The old value persists across unrelated requests.
ThreadLocalMapentries hold strong references → memory leak.
try { threadLocal.set(someValue); // ... business logic } finally { threadLocal.remove(); // ✅ ALWAYS clean up }
InheritableThreadLocal
If you need child threads to inherit the parent's ThreadLocal value, use InheritableThreadLocal. However, this does not work with thread pools since pool threads are not "children" of submitting threads.