Since it was founded by Internet companies " Rocket making " After the difficulty of interview , as a warning for the future , Then I gathered up my mind , Start from the basic knowledge point to develop carpet learning . Every non genius programming ape has a right 35 Fear of age , And the best way to eliminate fear is to face it , See it , Even across it , Learning is a growing weapon for ordinary people in this world , Got it , To fight against a rough life .

I read several articles recently about ThreadLocal Interview questions and technology blog , Let's make a summary with the source code , In order to facilitate the later self review .

Key points of this paper :

1,ThreadLocal How to play a role ?

2,ThreadLocal The subtlety of design

3,ThreadLocal Memory leak

4, How to let the new thread inherit the original thread's ThreadLocal?

Start next .

One ,ThreadLocal How to play a role ?

First of all, a local demo, It's a similar routine at work , Tell me first ThreadLocal, And then call it. set Method to store a specific object , But don't forget to add remove, Here is an example of a mistake ...
1 public class ThreadLocalDemo { 2 3 private static ThreadLocal<String>
threadLocal =new ThreadLocal<String>(); 4 5 public static void main(String[]
args) { 6 threadLocal.set("main thread"); 7 new Thread(() -> { 8
threadLocal.set("thread"); 9 }).start(); 10 } 11 }
Follow up set method :
1 public void set(T value) { 2 Thread t = Thread.currentThread(); 3
ThreadLocalMap map = getMap(t); // 1, obtain map 4 if (map != null) 5 map.set(this,
value); // 2, Put in value6 else 7 createMap(t, value); // 3, initialization map 8 }
stay threadLocal Of set There are three main methods , The first method is to remove the current thread threadLocals Get from map, The map yes Thread A member variable of class .


  If the thread is newly created ,threadLocals This value must be null, The method is entered 3 createMap in ( as follows ) Create a new one ThreadLocalMap
, Save to current ThreadLocal Objects and value.
1 void createMap(Thread t, T firstValue) { 2 t.threadLocals = new
ThreadLocalMap(this, firstValue); 3 }
Relatively, the most complex is the method 2 map.set() method , as follows , The method code is located in ThreadLocal Inner class of ThreadLocalMap in .
1 private void set(ThreadLocal<?> key, Object value) { 2 3 // We don't use
a fast path as with get() because it is at 4 // least as common to use set() to
create new entries as 5 // it is to replace existing ones, in which case, a fast
6 // path would fail more often than not. 7 8 Entry[] tab = table; 9 int
len = tab.length; 10 int i = key.threadLocalHashCode & (len-1); //
1, Get what to store key Array subscript of 11 12 for (Entry e = tab[i]; 13 e != null; 14 e = tab[i =
nextIndex(i, len)]) { ///2, If the subscript location is empty , Then skip this for loop , If it is not empty, it will enter the internal judgment logic , Otherwise, move the array pointer down ***15
ThreadLocal<?> k = e.get(); 16 // 2.1
If not empty , Then judge key Is it the subscript of the original array Entry Object's key, Yes, replace it directly value that will do 17 if (k == key) { 18 e.value =
value;19 return; 20 } 21 // 2.2 If the Entry Of key yes null, Indicates that the weak reference has been recycled , Replace it at this time value
***22 if (k == null) { 23 replaceStaleEntry(key, value, i); 24 return; 25 } 26
}27 // 3, Description array i Location is empty , direct new One Entry assignment 28 tab[i] = new Entry(key, value); 29 int
sz = ++size; 30 if (!cleanSomeSlots(i, sz) && sz >= threshold) // 4, Clean up some useless data
***31 rehash(); 32 }
This method is annotated , For important places *** It's marked , Although it may not be clear about the intention and principle of each step , But you can know what you've done --- This is done in this method value Storage of objects .

When I write here ,BZ I don't think it's clear , Draw a picture and wake up :


  complete set After operation , Current thread ,threadLocal variable ,ThreadLocal object ,ThreadLocalMap The relationship between them is basically sorted out .

Insert an extension , Add some references .Java Strong references in unless the code actively modifies or holds the referenced variables to be cleaned up , Otherwise, the object the reference points to must not be recycled by the garbage collector ; Soft reference is only JVM Enough memory , The object the reference points to will not be garbage collected ; Weak reference means that only when garbage collection is carried out, the object has weak reference , Will be recycled .

Entry The weak reference implementation of the class is as follows :
1 static class Entry extends WeakReference<ThreadLocal<?>> { 2 /** The value
associated with this ThreadLocal.*/ 3 Object value; 4 5 Entry(ThreadLocal<?>
k, Object v) {6 super(k); 7 value = v; 8 } 9 }
Pit filling starts below .


Two ,ThreadLocal The subtlety of design

above ThreadLocalMap.set Method , What's the point of the second step, which marks three stars ?

  answer : Find first unoccupied subscript location
.ThreadLocalMap In Entry[] Array is a ring structure , adopt nextIndex Method can prove , When i+1 than len When I was older , return 0 I.e. initial position . When hash When in conflict ,HashMap Data is stored by concatenating linked lists at subscript locations , and ThreadLocalMap There won't be that much traffic , So it's a lighter solution hash Way of conflict - Move back one position , See if it's empty , If it's not empty, move back , Until you find an empty location .
1 private static int nextIndex(int i, int len) { 2 return ((i + 1 < len) ? i +
1 : 0); 3 }

Why write JDK Code guys are going to Entry Of key Set to weak reference ? Marked with three stars 2.2 Why key Would be null?

answer :key Set to weak reference for when threadLocal After being cleaned, the ThreadLocal Objects can also be cleaned up , avoid ThreadLocal Memory leaks caused by objects . This is also key yes null Why - When only key This weak reference points to ThreadLocal When object , A garbage collection will ThreadLocal Recycled . But this way can't avoid memory leak completely , Because looking back at the previous memory map ,key Although the object pointed to has been freed memory , however value Still there , And because of this value Corresponding key yes null, There's no place to use this value, be finished , Memory can't be freed .

At this time 2.2 The logic of , If current i Subscript key yes null, Description has been recycled , Then just take this place , No one's using it anymore .


The fourth step, which marks three stars cleanSomeSlots What is the responsibility of the method ?

  answer : This method is used to clear the part key by null Of Entry object . Why the removal part ? See how :
1 private boolean cleanSomeSlots(int i, int n) { 2 boolean removed = false;
3 Entry[] tab = table; 4 int len = tab.length; 5 do { 6 i = nextIndex(i,
len); 7 Entry e = tab[i]; 8 if (e != null && e.get() == null) { 9 n = len; 10
removed =true; 11 i = expungeStaleEntry(i); 12 } 13 } while ( (n >>>= 1) != 0);
14 return removed; 15 }
stay do/while In cycle , Every cycle n Move right one bit ( Incoming n Is the number of data stored in the array ), If you encounter a key by null Situation of ,
Indicates that there may be more than one such object in the array , So the n Set as the length of the entire array , Multiple cycles , And called expungeStaleEntry Method will key by null Of value Remove reference .cleanSomeSlots Method does not adopt the way of full loop traversal , Mainly for the efficiency of method implementation .

Let's talk about it in detail expungeStaleEntry Method logic , This method is specially used for cleaning key by null This kind of overdue data , And there's a side effect : Because hash Collision causes the object with subscript backward to shrink and compact , Improve the efficiency of traversal query .
1 private int expungeStaleEntry(int staleSlot) { 2 Entry[] tab = table; 3
int len = tab.length; 4 // 1, Clear the subscript of the input parameter value 5 // expunge entry at staleSlot 6
tab[staleSlot].value =null; 7 tab[staleSlot] = null; 8 size--; 9 //
2, Traversal from the index of input parameter , Go all the way to tab[i] be equal to null Stop at 10 // Rehash until we encounter null 11
Entry e;12 int i; 13 for (i = nextIndex(staleSlot, len); 14 (e = tab[i]) != null
;15 i = nextIndex(i, len)) { 16 ThreadLocal<?> k = e.get(); 17 if (k == null) {
// 2.1 If key by null, I'm looking for this kind of fish in troubled waters , It's fast after it has to be eliminated 18 e.value = null; 19 tab[i] = null; 20
size--; 21 } else { 22 int h = k.threadLocalHashCode & (len - 1); 23 if (h !=
i) { // 2.2 h That is, the current entry Of key Subscript position that should be in , If i Different , Explain this entry It was moved after subscript conflict 24 tab[i] = null
; // At this time, you should put the i Positional e Move to h position , So first tab[i] Set as null, And then tab[i] Positional e Deposit h position 25 26 // Unlike
Knuth 6.4 Algorithm R, we must scan until27 // null because multiple entries
could have been stale. 28 while (tab[h] != null) // 2.3
Through while Loop to find h And the first null Subscript location of , This is where it's stored e Location of 29 h = nextIndex(h, len); 30
tab[h] = e; 31 } 32 } 33 } 34 return i; 35 }

Why should thread related variables be stored in this way ? Why not ThreadLocal Define a Map Member variables for ,key It's threads ,value Is the object to be stored , This design is not more concise and easy to understand ?

answer : This design can achieve the optimal access efficiency and space occupation . First look at access efficiency , If we use a common way of thinking Map To store key-value, There must be access conflicts when multithreading access , Even with ConcurrentHashMap There will also be performance consumption caused by lock competition , And now this will map Deposit Thread Design in , It ensures that a thread can only access its own map, And it's a single thread. There's no thread safety problem , Don't be too cool .


Three ,ThreadLocal Memory leak

In the example at the beginning of the article , use static Decorated ThreadLocal, Is it necessary to do so ? What's the role ?

answer : use static modification ThreadLocal variable , During the execution of the whole thread ,Map In key Will not be recycled ( Because there is a strong reference to a static variable ), So you can pick it up whenever you want , And it's the same from the beginning to the end threadLocal variable ( again new One exception ), Deposit map Only one subscript position is occupied in the middle time , No uncontrollable memory overrun . thus it can be seen , Set to static It's not entirely necessary , But it works .

ThreadLocal For key by null Situation of , Clean up in several different positions , To avoid memory leaks , Whether this can completely avoid memory leakage ? If not , How to avoid it completely ?

answer : It can avoid memory leakage to the greatest extent , But it can't be completely avoided . When the thread finishes executing, it will ThreadLocalMap Memory release , But if it is a thread in the thread pool , Reuse all the time , So it's Map In value The more data there is, the less free it is, causing memory leaks . How to avoid ? After use finally Medium tune remove Method , The way that the elders have written , It can be used .


in addition ,threadLocal Variable cannot be local , because key Is weak reference , If set to local variable , After the method is executed, only weak references are left , Could be released ,key Change to null, This is a departure ThreadLocal The original intention of sharing the same variable when the same thread passes through multiple methods .


Four , How to let the new thread inherit the original thread's ThreadLocal?

  answer :new One InheritableThreadLocal object set Data is enough , It will be saved to the current Thread Member variables for  inheritableThreadLocals in . When in the current thread new When a new thread , In the new thread init The current thread's inheritableThreadLocals Save to new thread , Complete data inheritance .


 Old Thread(ZZQ): I've taught you all my life , If you don't hurry, you'll be in trouble ?

New Thread(Pipe River): ...

©2019-2020 Toolsou All rights reserved,
Python Basic knowledge and notes Programmer Tanabata Valentine's Day confession code NOI2019 travels China's longest high speed rail officially opened ! The fastest way to finish the race 30.5 hour C Language programming to find a student's grade Software testing BUG describe ESP8266/ESP32 System : Optimize system startup time Unity Scene loading asynchronously ( Implementation of loading interface ) Baidu , Ali , Tencent's internal position level and salary structure , With job suggestions !PYTHON Summary of final review