ThreadLocal
ThreadLocal is called Thread local variable. It creates a copy of the variable in each Thread. Each Thread accesses and modifies the copy of the variable in this Thread, but the variables between threads cannot access each other. ThreadLocal is not a Thread.
ThreadLocal has four methods:
ThreadLocal action
ThreadLocal allows the thread to monopolize resources and store them inside the thread to avoid the decline of CPU throughput caused by thread congestion.
The same threadLocal is used, but the variables of each thread are independent and invisible to other threads. There is no need for each thread to new an object, which reduces the memory overhead.
Detailed explanation of ThreadLocal method
public class ThreadLocalTest { public static void main(String[] args) { ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); new Thread(new Runnable() { @Override public void run() { try{ threadLocal.set(1); System.out.println(threadLocal.get()); }finally { threadLocal.remove(); } } }, "Thread1").start(); new Thread(new Runnable() { @Override public void run() { threadLocal.set(2); System.out.println(threadLocal.get()); } }, "Thread2").start(); new Thread(new Runnable() { @Override public void run() { System.out.println(threadLocal.get()); } }, "Thread3").start(); } }
1 2 null
You can see that each thread uses a reference to the same threadLocal, but variables between threads cannot access each other.
How does ThreadLocal create a replica? (how to maintain variables)
Each Thread contains a ThreadLocalMap. The key of ThreadLocalMap is the ThreadLocal object and the value is the exclusive data.
Each Thread maintains a ThreadLocalMap mapping table. The key of this mapping table is the ThreadLocal instance itself, and the value is the Object that really needs to be stored.
In other words, ThreadLocal itself does not store values, it is just used as a key to let the thread obtain values from ThreadLocalMap.
ThreadLocal memory leak problem
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); //Continue to dig deeply. key is a weak reference and points to ThreadLcoal object k with a weak reference value = v; } }
ThreadLocalMap uses the weak reference of ThreadLocal as the Key, and the weakly referenced objects will be recycled during GC.
ThreadLocalMap uses the weak reference of ThreadLocal as the key. If a ThreadLocal does not have an external strong reference to reference it, the ThreadLocal is bound to be recycled during system GC (why it is recycled, as described below). Then entries with null key will appear in ThreadLocalMap, so there is no way to access the value s of these entries with null key.
If the current thread does not end for a long time, the values of these null key entries will always have a strong reference chain: thread ref - > thread - > threalocal map - > Entry - > value can never be recycled, resulting in memory leakage.
The above summary is that the key is null and is recycled, but the value is still there. It can only be recycled after judgment during set and get.
So why can't value be set to weak reference?
If the vaule is designed as a weak reference, you may get null and meaningless.
Why use weak references instead of strong references?
Strong reference:
Object object= new Object();
Strong references are used the most. In any case, as long as the strong reference relationship still exists, the garbage collector will never recycle the referenced objects.
object =null
For an ordinary object, if there is no other reference relationship, it can be collected as garbage as long as it exceeds the scope of the reference or explicitly assigns the corresponding (strong) reference to null. Of course, the specific collection time depends on the garbage collection strategy.
Strong references are one of the main causes of JAVA memory leaks. When the memory space is insufficient, the Java virtual opportunity throws OutOfMemoryError to make the program terminate abnormally. However, note that throwing an error will not recycle these strongly referenced objects
Weak reference:
String str = new String("123"); WeakReference<String> weakReference = new WeakReference<>(str); str = null;
During a garbage collection cycle, the jvm finds an object with only weak references, and will reclaim its memory regardless of whether the current memory space is sufficient or not.
Therefore, weak references have a shorter life cycle than strong references.
There are four References: https://www.cnblogs.com/yanl55555/p/13365397.html
Understand from the previous figure:
Look at the figure. When the main thread ends, the stack frame is destroyed, and the strong reference ThreadLocal is gone. Look at the red part again,
If it is a strong reference, the k reference of an entry in the ThreadLocalMap of the thread also points to the ThreadLocal object. As a result, the ThreadLocal object pointed to by k and the object pointed to by v cannot be recycled by the jvm virtual machine gc, resulting in memory leakage.
If it is a weak reference, the ThreadLocal object can be recycled at the end of execution, because only the K weak reference of entry points to it. After ThreadLocal is recycled, k points to null, but v still has a value and there is a risk of memory leakage. There is no guarantee that there will be no memory leakage.
So why should ThreadLocal use weak references instead of strong references?
The conclusion is to reduce the risk of serious memory leakage.
As mentioned above, the key is a weak reference. When the key is null, the value is not null, so the value cannot be recycled, causing a memory leak.
Weak references also have the risk of memory leakage, and strong references are more. When using thread pool, the number of customized threads is not standardized. If strong reference is used, the risk of memory leakage is higher.
How to prevent memory leakage?
The value of entry mentioned above also has the risk of memory leakage.
ThreadLocal has methods: when calling get,set or remove methods, it will try to delete the entry with null key, which can free the memory occupied by the value object.
The correct example of the above demo should be:
new Thread(new Runnable() { @Override public void run() { try{ threadLocal.set(1); System.out.println(threadLocal.get()); }finally { threadLocal.remove(); //remove after use to prevent memory leakage } } }, "Thread1").start();
Core of remove method:
private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); //Call elimination method return; } } } private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; // expunge entry at staleSlot tab[staleSlot].value = null; //Assign the value of vaule to null tab[staleSlot] = null; size--;
There are also set methods:
// If key not found, put new entry in stale slot tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value);
reference resources:
https://blog.csdn.net/qq_33404395/article/details/82356344
https://www.cnblogs.com/shen-qian/p/12108655.html