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);

eachThreadAll of them have oneThreadLocalMapAnd theThreadLocalMapCan be stored asThreadLocalIs 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