introduction
Regardless of the actual project combat or an interview, ThreadLocal
is not open around the topic, this paper from the perspective of the source and everyone to discuss the next ThreadLocal
mystery.
ThreadLocal
What is? It can do?ThreadLocal
Source code analysis- to sum up
First, ThreadLocal
what is? It can do?
ThreadLocal
Is a thread local variable, which means that variables are thread-exclusive, is not shared with other threads, it does not solve the problem of multi-threaded shared variables.
So ThreadLocal
with different thread synchronization mechanism, thread synchronization mechanisms are multiple threads share the same variable, and ThreadLocal
every thread create a separate copy of the variable is, therefore each thread can be changed independently variable copy what they have, rather than It will affect other threads corresponding copy. It can be said ThreadLocal
is a multi-threaded environment variable provides an alternative solution ideas.
ThreadLocal
The idea is to use space for time, so that each thread can access their own a copy of this variable, the variable values do not interfere with each other, reducing the complexity of some public functions or variables across multiple components within the same thread pass.
Second, ThreadLocal
source code analysis
1, ThreadLocalMap
parsing
ThreadLocal
defined inside an ThreadLocalMap
inner class, ThreadLocalMap
the actual use Entry
to achieve key-value
storage, as follows:
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
...
}
ThreadLocalMap
Is the key thread isolation mechanism, can be seen from the above code Entry
is key
that ThreadLocal
, while value
that value. At the same time, Entry
also inherited WeakReference
, so that the Entry
corresponding key
( ThreadLocal
reference example) as a weak reference.
We mainly look at the core getEntry()
, set(ThreadLocal> key, Object value)
the method
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);
}
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
// 根据 ThreadLocal 的散列值,查找对应元素在数组中的位置
int i = key.threadLocalHashCode & (len-1);
// 采用“线性探测法”,寻找合适位置
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// 若key 存在,直接覆盖
if (k == key) {
e.value = value;
return;
}
// key == null,但是存在值(因为此处的e != null),说明之前的ThreadLocal对象已经被回收了
if (k == null) {
// 用新元素替换陈旧的元素
replaceStaleEntry(key, value, i);
return;
}
}
//创建新元素
tab[i] = new Entry(key, value);
int sz = ++size;
// 如果没有清理陈旧的 Entry 并且数组中的元素大于了阈值,则进行 rehash
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
2, the core analytical method
(1) get ()
value of the current thread to return a copy of this thread-local in
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的成员变量 threadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// 从当前线程的ThreadLocalMap获取相对应的Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
// 获取目标值
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
First, get through the current thread corresponding member variables ThreadLocalMap
, and then ThreadLocalMap
get the current ThreadLocal
of Entry
the last acquisition target by Entry acquired result
.
(2) set (T value)
of this value for the current thread in the thread-local variable copy of the specified 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);
}
Get the current thread corresponding to ThreadLocalMap
, if not empty, then call ThreadLocalMap
the set()
method, key is present ThreadLocal
, and if not, then call the createMap()
method to create a new.
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
(3) initialValue ()
Returns the current thread is the initial value of this thread-local variable.
protected T initialValue() {
return null;
}
This method is defined as the protected
level and returns null
, need to subclass perform its function, so we use ThreadLocal
generally should override this method time. This method does not show the call, only the first call get()
or set()
will be executed when the method, and only performed once.
(4) remove ()
remove the current thread's value for this thread-local variable.
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
Third, the summary
1, when multiple threads to acquire a shared variable, the requirements to obtain a copy of the initial value of this variable. A copy of each thread to store this variable, change this variable does not affect copies of the variable itself. For multiple threads to complete the operation dependent variable values of different scenes. such as:
- Switching multiple data sources
- spring declarative transaction
2, will be ThreadLocal
provided private static
, so ThreadLocal
will try and recovered together with the thread itself.