当前位置:网站首页>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 .
边栏推荐
- 写入速度提升数十倍,TDengine 在拓斯达智能工厂解决方案上的应用
- How to empty uploaded attachments with components encapsulated by El upload
- Idea debugs com intellij. rt.debugger. agent. Captureagent, which makes debugging impossible
- The popularity of B2B2C continues to rise. What are the benefits of enterprises doing multi-user mall system?
- 22-07-04 Xi'an Shanghao housing project experience summary (01)
- Viewpager pageradapter notifydatasetchanged invalid problem
- 解决Navicat激活、注册时候出现No All Pattern Found的问题
- The writing speed is increased by dozens of times, and the application of tdengine in tostar intelligent factory solution
- Kotlin introductory notes (VIII) collection and traversal
- C语言-从键盘输入数组二维数组a,将a中3×5矩阵中第3列的元素左移到第0列,第3列以后的每列元素行依次左移,原来左边的各列依次绕到右边
猜你喜欢
Tdengine already supports the industrial Intel edge insight package
一篇文章带你走进cookie,session,Token的世界
Unity skframework framework (XXII), runtime console runtime debugging tool
Unity skframework framework (XXIII), minimap small map tool
22-07-04 Xi'an Shanghao housing project experience summary (01)
Principle and performance analysis of lepton lossless compression
Kotlin introductory notes (VIII) collection and traversal
一文读懂TDengine的窗口查询功能
干货整理!ERP在制造业的发展趋势如何,看这一篇就够了
Unity SKFramework框架(二十三)、MiniMap 小地图工具
随机推荐
[two objects merged into one object]
LeetCode 31. 下一个排列
The writing speed is increased by dozens of times, and the application of tdengine in tostar intelligent factory solution
H. 265 introduction to coding principles
LeetCode 496. Next larger element I
解决Navicat激活、注册时候出现No All Pattern Found的问题
MYSQL 对字符串类型排序不生效问题
观测云与 TDengine 达成深度合作,优化企业上云体验
Project practice | excel export function
测试老鸟浅谈unittest和pytest的区别
LeetCode 31. Next spread
Community group buying has triggered heated discussion. How does this model work?
[sourcetree configure SSH and use]
LeetCode 503. 下一个更大元素 II
TDengine可通过数据同步工具 DataX读写
Kotlin introductory notes (IV) circular statements (simple explanation of while, for)
Tutorial on building a framework for middle office business system
基于宽表的数据建模应用
Tdengine offline upgrade process
SQL learning group by multi table grouping scenario