Home  >  Article  >  Java  >  What is the reason why ThreadLocal in Java causes memory overflow (Out Of Memory)?

What is the reason why ThreadLocal in Java causes memory overflow (Out Of Memory)?

WBOY
WBOYforward
2023-04-23 23:58:091055browse

Cause analysis

What is the reason why ThreadLocal causes memory OOM?

The underlying layer of ThreadLocal stores data through ThreadLocalMap

The source code is as follows:

What is the reason why ThreadLocal in Java causes memory overflow (Out Of Memory)?

  • When we use ThreadLocal.set(), the value and key of the set (that is, the ThreadLocal class defined by the business itself) will be stored in the Entry[] array of ThreadLocalMap

The source code is as follows:

What is the reason why ThreadLocal in Java causes memory overflow (Out Of Memory)?

  • Entry implements a weak reference WeakReference, and the key of Entry (that is, the ThreadLocal class defined by the business party) will It is wrapped into a weak reference and used as the Entry key. The definition of Java's weak reference is that when the JVM performs a garbage collection scan and finds an object with only weak references, it will immediately recycle the object. This is a means of preventing memory overflow when ThreadLocal was originally designed.

The source code is as follows:

What is the reason why ThreadLocal in Java causes memory overflow (Out Of Memory)?

Although the key is packaged into a weak reference and will be recycled by the garbage collection mechanism, the value There may be a strong reference chain when the thread (Thread) does not die.

Since value is a strong reference, as long as Thread does not die, such as the thread pool, This strong reference chain will exist, then value will not be recycled, which may cause memory overflow.

The reference relationship is as follows: Thread ==> ThreadLocalMap == > Entry ==> value

But this action of eliminating the strong reference chain needs to be triggered by the business party in the case of get. Maybe the business party does not know how to get, or maybe the key of get is not empty. , and the expungeStaleEntry class will not be triggered. Therefore, developers should develop good habits and remember to call the ThreadLocal.remove() method or ThreadLocal.set(null)# when they are finished. ##Correct usage

public class ThreadLocalTest {
    /**
     * 未初始化的本地线程变量
     */
    private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
    public static void main(String[] args) throws InterruptedException {
        int threadNum = 10;
        List<Thread> threadList = Lists.newArrayList();

        for (int i = 0; i < threadNum; ++i) {
            long userId = i;
            Thread t = new Thread(() -> {
                try {
                    // 设置变量值
                    userThreadLocal.set(new User(userId, "lanxing" + userId, "2x"));
                    // 使用变量
                    doSomething();
                } finally {
                    // 移除变量
                    userThreadLocal.remove();   //移除ThreadLocal变量
                }
            }, "T" + i);
            threadList.add(t);
            t.start();
        }

        for (int i = 0; i < threadNum; ++i) {
            threadList.get(i).join();
        }
    }
    private static void doSomething() {
        log.info("Use ThreadLocal variable :{}", JSON.toJSONString(userThreadLocal.get()));
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class User {
    private Long id;
    private String name;
    private String level;
}

Print result:

14:30:26.790 [T2] INFO io.zhengsh.order.tool .ThreadLocalTest - Use ThreadLocal variable :{"id":2,"level":"2x","name":"lanxing2"}

14:30:26.789 [T5] INFO io.zhengsh.order.tool. ThreadLocalTest - Use ThreadLocal variable :{"id":5,"level":"2x","name":"lanxing5"}
14:30:26.792 [T0] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{"id":0,"level":"2x","name":"lanxing0"}

14:30:26.792 [T4] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{"id":4,"level":"2x","name":"lanxing4"}
14:30:26.792 [T8] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{"id":8,"level":"2x","name":"lanxing8"}
14:30:26.791 [T1] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{"id":1,"level":"2x","name":"lanxing1"}
14:30:26.792 [T7] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{"id":7,"level":"2x","name":"lanxing7"}
14:30:26.792 [T6] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable : {"id":6,"level":"2x","name":"lanxing6"}
14:30:26.791 [T9] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{ "id":9,"level":"2x","name":"lanxing9"}
14:30:26.790 [T3] INFO io.zhengsh.order.tool.ThreadLocalTest - Use ThreadLocal variable :{" id":3,"level":"2x","name":"lanxing3"}

The above is the detailed content of What is the reason why ThreadLocal in Java causes memory overflow (Out Of Memory)?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete