Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”
This article also participated in the “Digitalstar Project” to win a creative gift package and creative incentive money
Code shrimp is a sand carving and funny boy who likes listening to music, playing games and writing as well as most of his friends. The days are still very long, let’s refuel our efforts together 🌈
preface
bloggerPerennial wandering in the niuke face area, summed up byte, Ali, Baidu, Tencent, Meituan and other large manufacturers of high frequency examination questions, then will gradually share with you, looking forward to your attention, praise!
What is ThreadLocal?
ThreadLocal is a local thread copy variable utility class. It is mainly used to make a mapping between the private thread and the copy object stored by the thread, and the variables between the threads do not interfere with each other
How to use ThreadLocal?
ThreadLocl has three simple methods: get(), set(), and remove().
I believe that I do not need to say more friends also know what it means
public class Test01 {
public static void main(String[] args) {
ThreadLocal<Integer> local = new ThreadLocal<>();
local.set(10); System.out.println(local.get()); local.remove(); System.out.println(local.get()); }}Copy the code
Underlying principles of ThreadLocal
Open ThreadLocal’s set() method
- The first is to get the current thread
- Call the getMap(t) method to get the ThreadLocalMap
- If the map is not null, the set operation is performed. If the map is null, the map is created
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null)
map.set(this, value);
else
createMap(t, value);
}
Copy the code
Click the get() method
Similar to HashMap, small partners look at the source absolutely can understand
public T get(a) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map ! =null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if(e ! =null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
returnresult; }}return setInitialValue();
}
private Entry getEntry(ThreadLocal
key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if(e ! =null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
Copy the code
Click the remove() method
Much like a HashMap, you find the index, iterate over it and delete the key
public void remove(a) {
ThreadLocalMap m = getMap(Thread.currentThread());
if(m ! =null)
m.remove(this);
}
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);
return; }}}Copy the code
If you are careful, you may notice that all three methods need to be retrieved: == Current Thread and ThreadLocalMap==
So why??
Moving on to the source code, click on the getMap() method
As you can see, ThreadLocalMap fetches an object from Thread
How does ThreadLocal allow threads to interact with each other 😁
Since the ThreadLocalMap of the current thread is retrieved, the threads do not interfere with each other
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
Copy the code
Small partners can not feel that has mastered, is not over, this just which to which, 😁, we continue to see
Open the set method of ThreadLocalMap
private void set(ThreadLocal
key, Object value) {
Entry[] tab = table;
int len = tab.length;
// Hash retrieves the corresponding subscript, more on that later
int i = key.threadLocalHashCode & (len-1);
for(Entry e = tab[i]; e ! =null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<? > k = e.get();if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return; }}// Encapsulate as an Entry node
tab[i] = new Entry(key, value);
int sz = ++size;
if(! cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }Copy the code
If you are familiar with HashMap, you may find a familiar image: >==Entry==
WeakReference<ThreadLocal<? WeakReference<ThreadLocal<? > > = =
WeakReference: WeakReference
And there’s a code in there, if you noticed:tab[i] = new Entry(key, value);
I don’t have to tell you what this code means, but it encapsulates the key and value as an Entry node; According tomap.set(this, value);
==Key is the current ThreadLocal object and value is the value we want to set in ==
But there is an important point here: the call to keysuper(k)
I’m not going to mention one of ThreadLocal’s classic interview questions, but I’ll cover it later.
static class Entry extends WeakReference<ThreadLocal<? >>{
/** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}Copy the code
That’s it. Not surprisingly, ThreadLocal isn’t too difficult, so let’s wrap it up!
conclusion
The value that we set into the thread ends up in the ThreadLocalMap of the current thread, not in the ThreadLocal, which is simply an encapsulation of the ThreadLocalMap, passing the variable value. ThreadLocalMap (thread.currentThread ()); ThreadLocalMap (Thread t); ThreadLocalMap (Thread t);
eachThread
All of them have oneThreadLocalMap
And theThreadLocalMap
Can be stored asThreadLocal
Is key, and Object is value.
ThreadLocal
How does ThreadLocal resolve Hash conflicts?
Unlike HashMap, the ThreadLocalMap structure is very simple and has no next reference, which means that the resolution of Hash conflicts in ThreadLocalMap is not a list but a linear probe. The so-called linear detection is to determine the position of the element in the table array according to the hashcode value of the initial key. If it is found that this position has been occupied by other key values, the fixed algorithm is used to find the next position of a certain step length and judge successively until the position that can be stored is found.
With CAS, fixed values are incremented each time, so linear probing is used to resolve HasH collisions
Classic CAS
If you don’t know CAS, you can read my article, which is super detailed
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
Copy the code
ThreadLocal memory leak problems and solutions
ThreadLocal is referred to as a weak reference by the Key in the Entry in the ThreadLocalMap, so if a ThreadLocal has no external strong reference to reference it, then the ThreadLocal will be collected in the next JVM garbage collection. In this case, the key in the Entry is already collected, but the value is a strong reference that is not collected by the garbage collector. Thus, if the ThreadLocal thread keeps running, the value will never be collected, and a memory leak will occur.
== The solution ==
1. Remember to remove after use
2.ThreadLocal itself provides a solution to this problem.
Each set, get, and remove operation calls the three ThreadLocalMap methods, which directly or indirectly call expungeStaleEntry() each time they are called. This method removes entries with a null key to avoid memory leaks.
3. Decorate ThreadLocal with static
You can also use static to make the ThreadLocal a strong reference, which guarantees that the Entry value can be accessed at any time through the weak reference of the ThreadLocal, and thus cleared.
Reason: According to the reachable algorithm analysis, the object referenced by the static attribute can be used as GC Roots root node, which ensures that ThreadLocal is unrecyclable object
❤ finally
I am aCode pipi shrimp, a prawns lover who loves to share knowledge, will update useful blog posts in the future, looking forward to your attention!!
Creation is not easy, if this blog is helpful to you, I hope you can == one key three even oh! Thank you for your support. See you next time