当前位置:网站首页>ThreadLocal source code learning
ThreadLocal source code learning
2022-07-05 09:46:00 【Black Mountain demon 2018】
I'm learning EventBus When I saw the source code ThreadLocal, After consulting relevant materials, we know ThreadLocal There are quite a lot of places to use , So simply analyze it here ThreadLocal Principle and problems of
What is? ThreadLocal
ThreadLocal Is a tool class that can help threads store copies of variables , Why is it a variable copy , Because when multiple threads access the same variable ,ThreadLocal Each thread will be mapped to this variable one by one ( Note that the one-to-one mapping here is just a pseudo concept ), In this way, each thread corresponds to a copy of this variable , They don't influence each other , Mutual interference , Especially in the case of high concurrency , Each thread can pass through ThreadLocal Get the corresponding information to operate .
Realize the idea
see Thread Source code can be found ,Thread There is one in the class ThreadLocal.ThreadLocalMap A member variable of type threadLocals, That is, each thread has a separate ThreadLocal.ThreadLocalMap. and ThreadLocal.ThreadLocalMap There's a Entry Array ,Entry It's a key-value Form storage class , among key yes ThreadLocal Weak references to objects ,value Is the copy variable to be saved .ThreadLocal I'm giving everyone Thread When saving data, it is based on the current ThreadLocal The weak reference of the instance is key, Insert data into your ThreadLocalMap among , So different threads are based on key( The same ThreadLocal Weak references to instances ) Reading and writing data do not affect each other , Mutual interference .
Now let's take a look at ThreadLocal Of Code chip
ThreadLocal The core approach
// Get the copy variable value stored by the current thread , If the current thread does not store this value , Then return to initialValue() Method return value
public T get()
// Initialize the copy variable of the current thread
private T setInitialValue()
// Set the copy variable of the current thread
public void set(T value)
// Remove the copy variable of the current thread
public void remove()
// Initialize the copy variable of the current thread
protected T initialValue()
ThreadLocal Core inner class
public T get()
public T get() {
// Get the current thread
Thread t = Thread.currentThread();
// Gets the current thread's ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// adopt ThreadLocal Object acquisition Entry object
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
// If map by null, Then build map
return setInitialValue();
}
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
// If e Not for null And key Not recycled and e Of key Value weak reference points to ThreadLocal And key equal
// Then return to the entry object
if (e != null && e.get() == key)
return e;
else
// Otherwise, continue the linear search
return getEntryAfterMiss(key, i, e);
}
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e){
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal<?> k = e.get();
// Find the target , Go straight back to entry object
if (k == key)
return e;
// If key The value points to ThreadLocal Object is recycled , Then hold expungeStaleEntry
// Clean up
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
// because staleSlot Positional entry Object's key The pointing area has been recycled , So manually put
//tab[staleSlot] as well as tab[staleSlot].value Set as null
// The second thing , from staleSlot To traverse the , For non empty on each position entry Adjust the position
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// because key ThreadLocal The weak reference of has been set to null Being recycled or about to be recycled , So will
//entry Of value Also set to null,entry Also set to null
tab[staleSlot].value = null;
tab[staleSlot] = null;
//size reduce 1
size--;
Entry e;
int i;
for (i = nextIndex(staleSlot, len);(e = tab[i]) != null;i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
if (k == null) {
// If key ThreadLocal The weak reference of has been set to null Being recycled , Will
//entry Of value Also set to null,entry Also set to null, Simultaneous size reduction 1
e.value = null;
tab[i] = null;
size--;
} else {
// If not recycled , Then get k Of hash value , Determine whether it is the current position ,
// If not , From k The position starts traversing until it is found entry by null When , Will the current i Positional
//entry Assign values to the tab[h] On , At the same time, the current i Positional entry The object is set to null
int h = k.threadLocalHashCode & (len - 1);
if (h != i) {
tab[i] = null;
// Unlike Knuth 6.4 Algorithm R, we must scan until
// null because multiple entries could have been stale.
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
}
}
return i;
}
private T setInitialValue()
private T setInitialValue() {
// Get the initial default value
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
// You can see here that Thread Of ThreadLocalMap Member variable assignment , Enter again ThreadLocalMap Constructor to see
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
private static final int INITIAL_CAPACITY = 16;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
// The size is 16 Of entry An array of objects
table = new Entry[INITIAL_CAPACITY];
//firstKey.threadLocalHashCode And INITIAL_CAPACITY Modulo get hash value , It is also the position in the array
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
public void remove()
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
// according to ThreadLocal Object delete variable copy
m.remove(this);
}
private void remove(ThreadLocal<?> key) {
// obtain entry Array
Entry[] tab = table;
// Get array length
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
// Traversing an array , When it finds key when , perform e.clear(), Show weak references set to null
// At the same time expungeStaleEntry() Method
for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}
public void set(T value)
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//ThreadLocalMap set
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
// Traverse entry Array
for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// If we find the corresponding key, Then cover the original value
if (k == key) {
e.value = value;
return;
}
// If key Has been recovered , Replace those that are about to expire entry
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
//ThreadLocal The inner class of
static class ThreadLocalMap {
// You can see here Entry Class is key-value Data structure of , also Entry(key) Is holding
//ThreadLocal The soft references
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
// Initial capacity , It has to be for 2 The power of
private static final int INITIAL_CAPACITY = 16;
//entry Array , The size must be 2 The power of
private Entry[] table;
//entry Array size
private int size = 0;
private int threshold; // Default to 0
}
// Return to the next index
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
// Return to previous index
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
It can be seen that ThreadLocalMap Maintenance of tab Array is a ring structure , Every object in the array is Entry object (key-value Structure ), One ThreadLocalMap Can store multiple ThreadLoad object key value .
ThreadLocal The problem
ThreadLocal.ThreadLocalMap Use ThreadLocal Weak reference of object as Entry Of key, once ThreadLocal Object is recycled , namely key by null, If there are hundreds stored in a thread ThreadLoad Object space , Then there is key by null Of Entry There will be more and more objects , Plus, there is always the possibility that this thread will not end , At this time, memory leakage will occur .
So here comes the question , At this time, it will be considered as weak reference key Value causes Entry Objects that cannot be reclaimed and thus memory leaks . It's not , Let's look at the following two situations :
1.key Use strong references : It's recycling ThreadLocal The object is , however ThreadLocalMap And hold ThreadLocal A strong reference to , If it is not manually set to null, be ThreadLocal Will not be recycled , Lead to Entry Memory leak .
2.key Using weak references : It's recycling ThreadLocal The object is , because ThreadLocalMap hold ThreadLocal The weak references , Even if it is not manually set to null,ThreadLocal It will also be recycled .value The next time ThreadLocalMap call set,get,remove Will be cleared when .
So the essence of the problem is that there is no manual key Set as null.
ThreadLocal It's by putting key Set to weak reference , And at the same time use set,get,remove Method to manually delete key by null Of Entry Object to avoid memory leaks . When ThreadLocal A lot of storage Key by null Of Entry When , Instead of calling remove、get、set Method , That will lead to a memory leak .
边栏推荐
- 【组队 PK 赛】本周任务已开启 | 答题挑战,夯实商品详情知识
- 【对象数组a与对象数组b取出id不同元素赋值给新的数组】
- [listening for an attribute in the array]
- What about wechat mall? 5 tips to clear your mind
- [object array A and object array B take out different elements of ID and assign them to the new array]
- 搞数据库是不是越老越吃香?
- 【js 根据对象数组中的属性进行排序】
- From "chemist" to developer, from Oracle to tdengine, two important choices in my life
- OpenGL - Model Loading
- LeetCode 496. 下一个更大元素 I
猜你喜欢
Project practice | excel export function
OpenGL - Model Loading
Figure neural network + comparative learning, where to go next?
idea用debug调试出现com.intellij.rt.debugger.agent.CaptureAgent,导致无法进行调试
La voie de l'évolution du système intelligent d'inspection et d'ordonnancement des petites procédures de Baidu
LeetCode 556. 下一个更大元素 III
How do enterprises choose the appropriate three-level distribution system?
LeetCode 503. Next bigger Element II
Tdengine connector goes online Google Data Studio app store
Mobile heterogeneous computing technology GPU OpenCL programming (Advanced)
随机推荐
解决Navicat激活、注册时候出现No All Pattern Found的问题
7 月 2 日邀你来TD Hero 线上发布会
What are the advantages of the live teaching system to improve learning quickly?
搞数据库是不是越老越吃香?
一文读懂TDengine的窗口查询功能
A keepalived high availability accident made me learn it again
oracle 多行数据合并成一行数据
【js 根据对象数组中的属性进行排序】
LeetCode 31. 下一个排列
SMT32H7系列DMA和DMAMUX的一点理解
Evolution of Baidu intelligent applet patrol scheduling scheme
Nips2021 | new SOTA for node classification beyond graphcl, gnn+ comparative learning
[reading notes] Figure comparative learning gnn+cl
单片机原理与接口技术(ESP8266/ESP32)机器人类草稿
TDengine 离线升级流程
[listening for an attribute in the array]
uni-app---uni. Navigateto jump parameter use
Kotlin introductory notes (IV) circular statements (simple explanation of while, for)
Kotlin introductory notes (III) kotlin program logic control (if, when)
Lepton 无损压缩原理及性能分析