[ThreadLocal] Points to note in the actual development of ThreadLocal

ThreadLocal memory leak

Memory leak: The object is no longer used, but still resides in memory.

Structure of Entry in ThreadLocalMap

static class Entry extends WeakReference<ThreadLocal<?>> {
    
    
    Object value; // ThreadLocal变量值
    Entry(ThreadLocal<?> k, Object v) {
    
    
        super(k);
        value = v;
    }
}

The bottom layer of the ThreadLocalMap is the Entry array, the key of the Entry is ThreadLocal, and the value is the value of the ThreadLocal variable of the thread. The internal Entry class inherits the WeakReference class, which is a weak reference. We can see that each Entry contains both a weak reference to key and a strong reference to value.

The characteristic of weak references is that if the object is only associated with weak references (without any strong references), then the object can be recycled. Weak references will not prevent GC.

Under normal circumstances, when the thread terminates, the thread's ThreadLocalMap value is set to null. Because there is no strong reference, the value stored in ThreadLocal will be recycled by the garbage collector.

Strong reference chain

If the strong reference is always there, the garbage collector will not be collected, which may cause a memory leak.

If the thread pool is used, the thread will not terminate for a long time, then the key corresponding value will not be recycled, because there is the following call chain:

Thread -强引用-> ThreadLocalMap -强引用-> Entry(key为null)-强引用-> value

Thread and value have this strong reference link, which causes the value to be unable to be recycled, which leads to OOM.

This is handled in the JDK. In the resize operation inside the set, remove, and rehas methods of ThreadLocalMap, there are the following statements

if (k == null) {
    
     // 过期Entry,清空value
    e.value = null; // 利于垃圾回收

However, if ThreadLocal is not referenced, or the set, remove, and rehash methods are not called, the call chain will always exist, resulting in a memory leak of value.

solution

After using ThreadLocal, call the remove method to delete the corresponding Entry object to avoid memory leaks.

// 此时使用完ThreadLocal,回收该ThreadLocal
UserInfoHolder.holder.remove();

Thread pool is not suitable for using ThreadLocal.

NPE problem

public class WrongWayNPE {
    
    
    private static ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
    
    
        System.out.println(integerThreadLocal.get());
        System.out.println(getThreadLocal());
    }

    static int getThreadLocal() {
    
    
        return integerThreadLocal.get();
    }
}

For example, the generic type of ThreadLocal in the code is the Integer type. If the uninitialized value is directly transferred to the get() method, the value obtained is null. Null cannot be unboxed and replaced with a basic type, causing a null pointer exception.

Therefore, we understand that the NPE problem is not a ThreadLocal problem, but a developer code problem.

Guess you like

Origin blog.csdn.net/LIZHONGPING00/article/details/105211798