How ThreadLocal Can Cause Memory Leaks in Java Multithreading

This article explains how ThreadLocal creates per‑thread variable copies, demonstrates its usage with sample Java code, illustrates the internal storage structure, and reveals why improper handling can lead to memory leaks when thread‑local values persist in thread pools.

Lobster Programming
Lobster Programming
Lobster Programming
How ThreadLocal Can Cause Memory Leaks in Java Multithreading

ThreadLocal provides each thread with its own isolated copy of a variable, ensuring that values set in one thread do not affect others.

The following example shows how to create two ThreadLocal instances, assign values inside a new thread, and retrieve them:

public static void main(String[] args) {
    ThreadLocal<String> threadLocal = new ThreadLocal<>();
    ThreadLocal<String> threadLocal2 = new ThreadLocal<>();

    Thread thread = new Thread(() -> {
        threadLocal.set("longxia");
        threadLocal2.set("biancheng");

        String content = threadLocal.get();
        System.out.println(Thread.currentThread().getName() + " 内部的002: " + content);

        String content2 = threadLocal2.get();
        System.out.println(Thread.currentThread().getName() + " 内部的003: " + content2);
    }, "t1");
    thread.start();
}

The internal storage of ThreadLocal is a ThreadLocalMap held inside each thread. The diagram below illustrates the map’s structure, where each thread has its own map entries.

ThreadLocal internal map diagram
ThreadLocal internal map diagram

Each entry in ThreadLocalMap is an Entry object that extends WeakReference to the ThreadLocal key. The source of ThreadLocalMap looks like this:

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    // ...
}

Although the key (the ThreadLocal instance) may be reclaimed by the garbage collector, the associated value remains reachable as long as the thread itself lives. In thread‑pool scenarios, core threads are reused and not destroyed, so the value persists indefinitely, leading to a memory leak.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javamemory leakmultithreadingThreadLocal
Lobster Programming
Written by

Lobster Programming

Sharing insights on technical analysis and exchange, making life better through technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.