Take you to master the principle of ThreadLocal being bombarded by interviewers from big factories, don’t be silly to say that you don’t understand~~~

Article Directory



Preface

My wife Zenyi: Lei's Breath

Insert picture description here



What is ThreadLocal?

ThreadLocal is a local thread copy variable tool class. Mainly used to map 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 is relatively simple to use, there are three main methods: get(), set(), remove()

I believe I don’t need to say too much, everybody knows 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());

    }
}
Insert picture description here



The underlying principle of ThreadLocal


Click on the set() method of ThreadLocal

  • The first is to get the current thread
  • Call the getMap(t) method to get the ThreadLocalMap
  • If the map is not null, perform the set operation, if it is null, perform the map creation operation
public void set(T value) {
	
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}


Click on the get() method

Similar to HashMap, you can definitely understand the source code if you look at it yourself

public T get() {
    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;
            return result;
        }
    }
    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);
 }


Click on the remove() method

Similar to HashMap, find the index, traverse and delete because of the key

public void remove() {
	   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;
	       }
	   }
}

Careful friends may find that all three methods need to be obtained:Current Thread and ThreadLocalMap


So why is this? ? ?

Let's look at the source code and click on the getMap() method

It can be found that ThreadLocalMap obtains an object in Thread

I believe that everyone will understand how ThreadLocal makes each thread not interfere with each other😁

Because what is obtained is the ThreadLocalMap of the current thread, each thread does not interfere with each other
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
Insert picture description here

Don’t think you’ve mastered it, my friends, it’s not over yet, here is where, 😁, let’s see


Open the set method of ThreadLocalMap

private void set(ThreadLocal<?> key, Object value) {

     Entry[] tab = table;
     int len = tab.length;
     //hash获取对应下标,之后会讲
     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;
         }
     }
		
	//封装为Entry节点
     tab[i] = new Entry(key, value);
     int sz = ++size;
     if (!cleanSomeSlots(i, sz) && sz >= threshold)
         rehash();
 }

After reading the above source code, friends who are familiar with HashMap may find a familiar figure——>Entry

But this Entry is different from HashMap, itInherited WeakReference<ThreadLocal<?>>

WeakReference: weak reference

And there is a piece of code above, I don’t know if the friends noticed:tab[i] = new Entry(key, value);

I don’t need to say what this code means to believe, that is, to encapsulate the key and value as Entry nodes; according to map.set(this, value);this code, we can see,Key is the current ThreadLocal object, value is the value we want to set in

But here is another important point: that is to call the key super(k), I will not say more here for the time being, a classic interview question involving ThreadLocal will be explained in detail later in the article, friends should be patient and continue to watch! ! !

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

This is basically the end, don’t be surprised, ThreadLocal is not too difficult, so let’s make a summary first!



to sum up

We set the value into the final is on the current thread ThreadLocalMapin, there is not ThreadLocalon, ThreadLocalcan be understood as just ThreadLocalMapa package, passed variable values. ThrealLocalAfter Thread.currentThread()obtaining the current thread object in the class, you can directly getMap(Thread t)access the thread's ThreadLocalMapobject through directly .

Each Threadare provided with one ThreadLocalMap, and ThreadLocalMapmay be stored ThreadLocalas a key, Object value of object pairs.





How does ThreadLocal resolve Hash conflicts?

Unlike HashMap, ThreadLocalMap has a very simple structure and no next reference, which means that the method of resolving Hash conflicts in ThreadLocalMap is not a linked list method, but a linear detection method. 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, a fixed algorithm is used to find the next position of a certain step, and then judge in turn. Until you find a place that can be stored.

Insert picture description here

Use CAS, increase the fixed value each time, so the linear detection method is used to solve the HasH conflict

Insert picture description here

Classic CAS

If you don’t understand CAS, you can read my article. It’s written in super detail.

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



ThreadLocal memory leak problem and solution

ThreadLocal is referenced by the Key in Entry as a weak reference in ThreadLocalMap, so if ThreadLocal does not have an external strong reference to refer to it, then ThreadLocal will be recycled in the next JVM garbage collection. At this time, the key in the Entry has been recycled, but the value is a strong reference and will not be recycled by the garbage collector, so if the ThreadLocal thread continues to run, the value will never be recycled, which will cause a memory leak.


Insert picture description here



Solution

1. Remember to remove after use

2. ThreadLocal itself provides a solution to this problem.

Each operation set, get, remove operation, will call the appropriate methods ThreadLocalMap of three, three ThreadLocalMap method is invoked each time invoked a expungeStaleEntry () method will be directly or indirectly, this method will be the key is null Entry is deleted to avoid memory leaks.


Insert picture description here


3. Use static to decorate ThreadLocal

You can also use static to modify ThreadLocal to ensure that ThreadLocal is a strong reference, and you can also ensure that you can access the value of Entry through the weak reference of ThreadLocal at any time, and then clear it.

Reason: According to the analysis of the reachability algorithm, the object referenced by the class static property can be used as the root node of GC Roots, which guarantees that ThreadLocal is an unrecyclable object



At last

I am a CRUD master , a Pippi shrimp lover who loves to share knowledge. In the future, I will continue to update blog posts that are beneficial to everyone. I look forward to your attention! ! !

It’s not easy to create. If this blog post is helpful to you, I hope you guys canOne-click three consecutive!, Thanks for your support, see you next time~~~

Share outline

Dachang Interview Questions Column


Java From Entry to Grave Learning Route Catalog Index


Open Source Crawler Example Tutorial Catalog Index

For more exciting content to share, please click Hello World (●'◡'●)


Insert picture description here