ThreadLocal
直译为线程本地,个人理解为线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。在多线程中,为保证多个线程对共享变量的安全访问,可以将变量放到ThreadLocal类型的对象中,使变量在每个线程中都有独立拷贝,不会出现一个线程读取变量时而被另一个线程修改的现象。
ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的静态内部类
ThreadLocalMap 维护了一个 Entry 数组,Entry 的 key 是 ThreadLocal 对象,value 是存入的对象,一个 ThreadLocal 只能存储一个Object对象,如果需要存储多个Object对象那么就需要多个ThreadLocal
Entry 的 key 引用 ThreadLocal 是弱引用
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;
}
}
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
ThreadLocal的使用
通过get、set来获取、设置存储对象,其中get方法会从当前线程中取出
ThreadLocalMap,然后把当前的ThreadLocal作为Key,ThreadLocal中的Object作为值存到线程的threadLocals中去
- 以下为JDK8中的源码,需要特别注意的是,早期的ThreadLocalMap的结构并不是这样,早期的Key是Thread,而Thread死亡后Map中的Key会变为null,Value则无法回收,最终造成内存泄漏问题,而在JDK8中可以看到,ThreadLocalMap放入了Thread中,生命周期跟Thread保持一致,故即使Key是弱引用,可能会变成null,也不会造成严重的内存泄漏问题,因为线程的生命周期并不长
ThreadLocal.ThreadLocalMap threadLocals = null;
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();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
ThreadLocal的思考
今天与同事聊到ThreadLocal,同事提了一个问题
- 从代码功能上来看,ThreadLocal其实就类似一个工具类,本身并不包含数据与状态,那为什么不用static修饰?
经过验证,public T get()方法用static修饰时编译器会报错,因为ThreadLocal是带泛型的,无法在编译时确定具体类型,故只能通过new的方式创建
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。