As shown in the picture:
Next, we will use a simple example to show you the basic usage of ThreadLocal
package cuit.pymjl.thradlocal; /** * @author Pymjl * @version 1.0 * @date 2022/7/1 10:56 **/ public class MainTest { static ThreadLocal<String> threadLocal = new ThreadLocal<>(); static void print(String str) { //打印当前线程中本地内存中本地变量的值 System.out.println(str + " :" + threadLocal.get()); //清除本地内存中的本地变量 threadLocal.remove(); } public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { //设置线程1中本地变量的值 threadLocal.set("thread1 local variable"); //调用打印方法 print("thread1"); //打印本地变量 System.out.println("after remove : " + threadLocal.get()); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { //设置线程1中本地变量的值 threadLocal.set("thread2 local variable"); //调用打印方法 print("thread2"); //打印本地变量 System.out.println("after remove : " + threadLocal.get()); } }); t1.start(); t2.start(); } }
The running results are as shown in the figure:
Let’s first take a look at the class diagram structure of the ThreadLocal related class, as shown in the figure:
public void set(T value) {
// 1.获取当前线程(调用者线程)
Thread t = Thread.currentThread();
// 2.以当前线程作为key值,去查找对应的线程变量,找到对应的map
ThreadLocalMap map = getMap(t);
if (map != null) {
// 3.如果map不为null,则直接添加元素
map.set(this, value);
} else {
// 4.否则就先创建map,再添加元素
createMap(t, value);
}
}
void createMap(Thread t, T firstValue) {
/**
* 这里是创建一个ThreadLocalMap,以当前调用线程的实例对象为key,初始值为value
* 然后放入当前线程的Therad.threadLocals属性里面
*/
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap getMap(Thread t) {
//这里就是直接获取调用线程的成员属性threadlocals
return t.threadLocals;
}
get public T get() {
// 1.获取当前线程
Thread t = Thread.currentThread();
// 2.获取当前线程的threadlocals,即ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 3.如果map不为null,则直接返回对应的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
// 4.否则,则进行初始化
return setInitialValue();
}
The following is the code for setInitialValue ##<pre class='brush:php;toolbar:false;'>private T setInitialValue() {
//初始化属性,其实就是null
T value = initialValue();
//获取当前线程
Thread t = Thread.currentThread();
//通过当前线程获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
//如果map不为null,则直接添加元素
if (map != null) {
map.set(this, value);
} else {
//否则就创建,然后将创建好的map放入当前线程的属性threadlocals
createMap(t, value);
}
//将当前ThreadLocal实例注册进TerminatingThreadLocal类里面
if (this instanceof TerminatingThreadLocal) {
TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
}
return value;
}</pre>
I need to add some explanation here
. This class is new in jdk11 and does not exist in jdk8, so there is no relevant description of this class in many source code analyzes on the Internet. I took a look at the source code of this class, and its function should be to avoid the problem of ThreadLocal memory leaks (if you are interested, you can take a look at the source code, and please correct me if there are any errors). This is the official explanation: <pre class='brush:php;toolbar:false;'>/**
* A thread-local variable that is notified when a thread terminates and
* it has been initialized in the terminating thread (even if it was
* initialized with a null value).
* 一个线程局部变量,
* 当一个线程终止并且它已经在终止线程中被初始化时被通知(即使它被初始化为一个空值)。
*/</pre>
remove
public void remove() { //如果当前线程的threadLocals 变量不为空, 则删除当前线程中指定ThreadLocal 实例的本地变量。 ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) { m.remove(this); } }
Summary
Inside each thread there is a member variable named threadLocals, the type of this variable is Hash Map, where key is the this reference of the ThreadLocal variable we defined, and value is the value we set using the set method. The local variables of each thread are stored in the thread's own memory variable threadLocals. If the current thread never dies, these local variables will always exist, so it may cause memory overflow. Therefore, remember to call the remove method of ThreadLocal to delete after use. Local variables in threadLocals corresponding to the thread.
ThreadLocal memory leak
Why does a memory leak occur?
ThreadLocalMap uses the weak reference of ThreadLocal as the key. If a ThreadLocal does not have an external strong reference to refer to it, then the ThreadLocal will inevitably be recycled during the system GC.
In this way, the ThreadLocalMap will If an Entry with a null key appears, there is no way to access the value of these Entry with a null key. If the current thread does not end for a long time, there will always be a strong line for the value of these Entry with a null key. Reference chain: Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value can never be recycled, causing memory leaks. In fact, this situation has been taken into consideration in the design of ThreadLocalMap, and some protective measures have been added: all keys in the thread ThreadLocalMap that are null will be cleared during get(), set(), and remove() of ThreadLocal. value. However, these passive preventive measures cannot guarantee that there will be no memory leaks:
- Using static ThreadLocal extends the life cycle of ThreadLocal, which may lead to memory leaks
- Allocation uses ThreadLocal and no longer calls the get(), set(), remove() methods, which will lead to memory leaks
- Why use weak references?
Since we all know that using weak references will cause ThreadLocalMap memory leaks, why do officials still use weak references instead of strong references? This starts with the difference between using weak references and strong references:
If you use strong references: We know that the life cycle of ThreadLocalMap is basically the same as the life cycle of Thread. If the current thread is not terminated, then ThreadLocalMap will never be recycled by GC, and ThreadLocalMap holds the right to ThreadLocal. Strong reference, then ThreadLocal will not be recycled. When the thread life cycle is long, if it is not deleted manually, it will cause kv accumulation, resulting in OOM
If you use weak references: weak The object in the reference has a short declaration period, because during the system GC, as long as a weak reference is found, the object will be recycled regardless of whether the heap space is sufficient. When the strong reference of ThreadLocal is recycled, the weak reference held by ThreadLocalMap will also be recycled. If kv is not deleted manually, it will cause value accumulation and OOM
From the comparison, we can see that using weak references can at least ensure that OOM will not be caused by the accumulation of map keys, and the corresponding value can be cleared on the next call through the remove, get, and set methods. It can be seen that the root cause of memory leaks is not weak references, but the life cycle of ThreadLocalMap is as long as Thread, causing accumulation.
Solution
Since the root of the problem is the accumulation of value causing OOM, Then we take the right medicine and call the remove()
method every time we use ThreadLocal to clean it up.
The above is the detailed content of How to use Java ThreadLocal class. For more information, please follow other related articles on the PHP Chinese website!

JVM works by converting Java code into machine code and managing resources. 1) Class loading: Load the .class file into memory. 2) Runtime data area: manage memory area. 3) Execution engine: interpret or compile execution bytecode. 4) Local method interface: interact with the operating system through JNI.

JVM enables Java to run across platforms. 1) JVM loads, validates and executes bytecode. 2) JVM's work includes class loading, bytecode verification, interpretation execution and memory management. 3) JVM supports advanced features such as dynamic class loading and reflection.

Java applications can run on different operating systems through the following steps: 1) Use File or Paths class to process file paths; 2) Set and obtain environment variables through System.getenv(); 3) Use Maven or Gradle to manage dependencies and test. Java's cross-platform capabilities rely on the JVM's abstraction layer, but still require manual handling of certain operating system-specific features.

Java requires specific configuration and tuning on different platforms. 1) Adjust JVM parameters, such as -Xms and -Xmx to set the heap size. 2) Choose the appropriate garbage collection strategy, such as ParallelGC or G1GC. 3) Configure the Native library to adapt to different platforms. These measures can enable Java applications to perform best in various environments.

OSGi,ApacheCommonsLang,JNA,andJVMoptionsareeffectiveforhandlingplatform-specificchallengesinJava.1)OSGimanagesdependenciesandisolatescomponents.2)ApacheCommonsLangprovidesutilityfunctions.3)JNAallowscallingnativecode.4)JVMoptionstweakapplicationbehav

JVMmanagesgarbagecollectionacrossplatformseffectivelybyusingagenerationalapproachandadaptingtoOSandhardwaredifferences.ItemploysvariouscollectorslikeSerial,Parallel,CMS,andG1,eachsuitedfordifferentscenarios.Performancecanbetunedwithflagslike-XX:NewRa

Java code can run on different operating systems without modification, because Java's "write once, run everywhere" philosophy is implemented by Java virtual machine (JVM). As the intermediary between the compiled Java bytecode and the operating system, the JVM translates the bytecode into specific machine instructions to ensure that the program can run independently on any platform with JVM installed.

The compilation and execution of Java programs achieve platform independence through bytecode and JVM. 1) Write Java source code and compile it into bytecode. 2) Use JVM to execute bytecode on any platform to ensure the code runs across platforms.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Atom editor mac version download
The most popular open source editor

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Dreamweaver Mac version
Visual web development tools

SublimeText3 Linux new version
SublimeText3 Linux latest version

Dreamweaver CS6
Visual web development tools
