当前位置:网站首页>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 .
边栏推荐
- Community group buying has triggered heated discussion. How does this model work?
- 【sourceTree配置SSH及使用】
- LeetCode 496. 下一个更大元素 I
- Nips2021 | new SOTA for node classification beyond graphcl, gnn+ comparative learning
- C language - input array two-dimensional array a from the keyboard, and put 3 in a × 5. The elements in the third column of the matrix are moved to the left to the 0 column, and the element rows in ea
- 移动端异构运算技术-GPU OpenCL编程(进阶篇)
- 基于模板配置的数据可视化平台
- 写入速度提升数十倍,TDengine 在拓斯达智能工厂解决方案上的应用
- 【对象数组的排序】
- A detailed explanation of the general process and the latest research trends of map comparative learning (gnn+cl)
猜你喜欢
H.265编码原理入门
H. 265 introduction to coding principles
C language - input array two-dimensional array a from the keyboard, and put 3 in a × 5. The elements in the third column of the matrix are moved to the left to the 0 column, and the element rows in ea
How to implement complex SQL such as distributed database sub query and join?
Evolution of Baidu intelligent applet patrol scheduling scheme
E-commerce apps are becoming more and more popular. What are the advantages of being an app?
[sourcetree configure SSH and use]
Three-level distribution is becoming more and more popular. How should businesses choose the appropriate three-level distribution system?
Data visualization platform based on template configuration
Unity SKFramework框架(二十四)、Avatar Controller 第三人称控制
随机推荐
【数组的中的某个属性的监听】
如何正确的评测视频画质
Solve the problem of no all pattern found during Navicat activation and registration
Gradientdrawable get a single color
LeetCode 496. Next larger element I
Three-level distribution is becoming more and more popular. How should businesses choose the appropriate three-level distribution system?
VS Code问题:长行的长度可通过 “editor.maxTokenizationLineLength“ 进行配置
What are the advantages of the live teaching system to improve learning quickly?
Kotlin introductory notes (V) classes and objects, inheritance, constructors
90%的人都不懂的泛型,泛型的缺陷和应用场景
Wechat applet obtains household area information
为什么不建议你用 MongoDB 这类产品替代时序数据库?
Unity skframework framework (XXII), runtime console runtime debugging tool
TDengine 离线升级流程
[sourcetree configure SSH and use]
一篇文章带你走进cookie,session,Token的世界
Lepton 无损压缩原理及性能分析
Tutorial on building a framework for middle office business system
[how to disable El table]
A detailed explanation of the general process and the latest research trends of map comparative learning (gnn+cl)