Java: ThreadLocal parsing


foreword

ThreadLocal is a very important content in java. This article introduces the content of ThreadLocal as comprehensively as possible, including memory leaks, key weak references, etc.


1. What is ThreadLocal?

The first explanation: ThreadLocal is called a thread variable, which means that the variable filled in ThreadLocal belongs to the current thread, and the variable is isolated from other threads, which means that the variable is unique to the current thread. ThreadLocal creates a copy of the variable in each thread, so each thread can access its own internal copy variable

The second explanation: a ThreadLocal is shared in a thread and isolated between different threads. Each thread can only see the value of its own thread. This is the core function of ThreadLocal: to realize the scope of threads local variables.

The third explanation: The main solution of the ThreadLocal class is to let each thread bind its own value. The ThreadLocal class can be compared to a box for storing data, and the private data of each thread can be stored in the box.

If you create a ThreadLocal variable, each thread that accesses the variable will have a local copy of the variable, which is where the ThreadLocal variable name comes from. They can use the get() and set() methods to get the default value or change its value to the value of the copy saved by the current thread, thus avoiding thread safety problems.

insert image description here
insert image description here
Summary: Thread threads can have multiple shared variables maintained by ThreadLocal that are exclusive to their own threads (this shared variable is only shared in their own threads)
insert image description here

insert image description here

Two, ThreadLocal's memory leak problem

1. What is a memory leak?

A memory leak means that the program cannot release the requested memory space after applying for memory. The harm of a memory leak can be ignored, but the consequences of memory leak accumulation are very serious, because no matter how much memory, it will be used up sooner or later.
Broadly speaking, it means that the memory occupied by objects or variables that are no longer used cannot be reclaimed, which is a memory leak.

2. Why is there a memory leak problem?

insert image description here

Improper operation of ThreadLocal will cause memory leaks, the main reason is the design of Entry in its internal class ThreadLocalMap.

Entry inherits WeakReference<ThreadLocal<?>>, that is, the key of Entry is a weak reference. The characteristic of weak reference is that if there are only weak references in this object, it will be cleaned up in the next garbage collection. Therefore, the key will be recycled during garbage collection, but the value corresponding to the key will not be recycled, which will lead to a phenomenon: the key is null, and the value has a value.

If the key is empty, the value is invalid data. Over time, the accumulation of values ​​will lead to memory leaks.

ThreadLocal is like Thread when there is no strong reference to external objects. When GC occurs, the weak reference Key will be recycled, and the Value will not be recycled if it is a strong reference. If the thread that created ThreadLocal continues to run like a thread in the thread pool, then the Entry object The value may never be recycled, resulting in a memory leak
insert image description here

As can be seen from the above figure, hreadLocalMap uses the weak reference of ThreadLocal as the key. If a ThreadLocal does not have an external strong reference, the Key (ThreadLocal) is bound to be recycled by GC, which will cause the key in ThreadLocalMap to be null, while the value is still There is a strong reference, and only after the thread thread exits, the strong reference chain of value will be broken.

But if the current thread does not end for a long time, there will always be a strong reference chain in the value of these Entry whose key is null:

Thread Ref --> Thread  -->ThreaLocalMap  --> Entry -->value

That is, it can never be recycled, causing a memory leak.

When it needs to be specially emphasized, the entry's reference to the key (threadlocal) is a weak reference, and the reference to the value is a strong reference, but the external reference to threadlocal is a strong reference.
Therefore, when threadlocal is referenced externally, threadlocal will not be recycled by GC because there are strong references, but when threadlocal is no longer referenced externally, that is

 threadlocal = null

At this time, threadlocal only has a weak reference of entry, which will be recycled

3. How to solve the memory leak problem?

(1) ThreadLocal will automatically clear the value whose key is null

ThreadLocal's get(), set(), and remove() will clear all the values ​​whose key is null in the thread ThreadLocalMap.

(2) Call ThreadLocal.remove() in time after use

The emove method will actively clear the current key and value (Entry).
insert image description here

(3) Set ThreadLocal as a global variable

ThreadLocal is set as a global variable so that it cannot be recycled by GC (if it is used in a member variable, set the modifier to public static, ThreadLocal will not be recycled, and there will be no case where the key is null, and there will be no memory leak)

3. Can the key of Entry be set as a strong reference?

Can't!

When the key of ThreadLocalMap is a strong reference, when recycling ThreadLocal, because ThreadLocalMap still holds a strong reference to ThreadLocal, if it is not manually deleted, ThreadLocal will not be recycled, resulting in a memory leak of Entry

You should know that ThreadlocalMap is bound to the thread. If the thread is not destroyed and we no longer refer to a threadlocal, then the key-value pair will always exist in the map, which is for As far as the program is concerned, there is a memory leak.

In order to avoid this situation, as long as the key is set as a weak reference, then when GC occurs, the weak reference will be automatically cleaned up, that is to say: if a user A generates a copy of threadlocalA when executing the method, release After threadlocalA is created, as a weak reference, it will be cleaned up in the next garbage collection.

Moreover, ThreadLocalMap will clean up leaked entries during internal set, get and expansion, so there is no need to worry too much about memory leaks.

3. Can the value of Entry be set as a weak reference?

Can't!

If the value is designed as a weak reference, then it is very likely that when you need to fetch the value, the fetched value is a null.

The purpose of your use of ThreadLocal is to store this value in the current thread, and you want to take it out of the current thread directly when you need it, which means that your value, in addition to the current thread holding a strong reference to it, theoretically In other words, there should be no other strong references, otherwise you will not store the value into the current thread. But once you design the value that should be strongly referenced into a weak reference, then as long as jvm performs a gc operation, your value will be recycled directly. When you need to get a value from the current thread, you end up with null.

Guess you like

Origin blog.csdn.net/qq_46119575/article/details/131565307