先说一下,本篇文章,只是简单,阅读下源码,应对面试差不多够了,要深入理解,还请看源码
讲实话,看完源码,还是有点小迷,ThreadLocal源码,感觉优点乱。。
每个线程中都可以通过ThreadLocal定义一个独立的副本,不会影响到其他线程;
ThreadLocal主要属性和方法
-
一个静态内部类:
ThreadLocalMap
-
维护了一个静态内部类Entry,Entry类下有一个value属性,就是存储线程通过ThreadLocal放的值;
-
维护了一个Entry[ ] table数组;
此数组里面存放的是线程对象;
-
这里注意:Entry是弱引用,最后会说一下,弱引用使用场景;
-
-
get方法,后面说
-
set方法,后面说
下面是提取出来的主要的源码:
public class ThreadLocal<T> {
static class ThreadLocalMap {
// 每个线程一个Entry,对应唯一的Value,弱引用对象
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
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);
}
}
// 设置值,后面讲
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// 主要是getEntry方法!后面会详解
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
// 我们在set值的时候,ThreadLocalMap一般是没有创建的
// 而是通过createMap(t, value);创建一个
// 这个初始化,会直接通过构造方法,把要放的值,放进去!
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// 删除,直接删除线程对应的Entry对象
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
}
还要知道:
每一个Thread对象下都有一个ThreadLocalMap对象:
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
......
}
get、set
-
ThreadLocalMap
下维护一个table数组,初始容量为16; -
提供
set()
方法:根据线程对象,拿到此
TheadLocal
下的ThreadLocalMap
对象ThreadLocalMap
对象只有一个!map.getEntry
根据线程ID,锁定线程对应的Entry对象;找到这个Entry对象,拿到里面的value,就是此线程存放的值;
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
-
set()方法
比较简单;不说了。。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); // 这里是key是线程对象,value是要村的值 else createMap(t, value); }
弱引用Entry
Entry对象是弱引用!!存在内存泄露风险!
弱引用:GC触发,就会回收的对象!
所以,只能用于临时存储,即存即用的场景,如果是强依赖这个副本,则不适合使用ThreadLocal
!