主要内容
- ThreadLocal
- 基本操作
- 实现原理
前言
本文主要深入了解ThreadLocal
的内部实现原理,实习项目用到过ThreadLocal,因此了解它的原理以及运用场景还是很有用的。ThreadLocal
顾名思义是线程本地,它指的是为维护的变量在每一个线程内创建副本,每个线程可以独立访问使用自己的变量副本,线程之间相互不干扰。
总结起来,其实ThreadLocal
提供了线程的局部变量,在多线程环境下这些变量能独立于其他线程内的变量,一般ThreadLocal
都是private static
类型的,用于关联线程上下文。
基本操作
先来看看ThreadLocal的基本操作。
构造函数
public ThreadLocal() {
}
发现构造方法里啥也没做。接下来看其他方法。
设值方法
/**
* initialValue方法会在第一次调用get方法时被调用,但是如果刚开始就调用了set方法,这个函数就不会调用。一般初始化方法只会调用一次,除非手动调用remove方法后又调用了get函数
* @return the initial value for this thread-local返回threadLocal的初始值
*/
protected T initialValue() {
return null;
}
一般建议使用匿名内部类重写这个方法,来指定初始值,例如:
private static final ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return Integer.valueOf(1);
}
};
深入
get方法源码
想知道ThreadLocal
怎么实现之前,先来看看get
源码
public T get() {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//根据当前线程获取到ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//当前ThreadLocal的引用作为key
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;//由线程类的threadLocals变量获取
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
void createMap(Thread t, T firstValue) {//创建新的ThreadLocalMap
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
流程主要是:
1.先获取当前线程
2.然后调用getMap
方法根据当前线程获取到ThreadLocalMap,观察源码发现ThreadLocalMap
是由线程类的threadLocals
变量获取
3.如果获取到的map不为空的话,则将当前ThreadLocal
的引用作为key,返回ThreadLocalMap
的节点Entry类
4.如果节点不为null的话,直接返回对应的value 值
5.如果map为空或获取到的节点为null,调用setInitialValue
设值初始值
实现原理
让大家来思考下如果是你的话你会怎么实现,我首先想到的是为ThreadLocal类创建一个维护ThreadLocalMap的映射表,然后由Thread的ID值作为key值,value值存储实例对象。
来看看JDK中ThreadLocal的实现原理:
ThreadLocal.ThreadLocalMap threadLocals = null;
在Thread
类中维护一个变量表示ThreadLocalMap
映射表,key值为当前ThreadLocal
的引用,value值为真正需要存储的对象。
我们会发现,用ThreadLocal作为key值,比用Thread线程ID作为key,创建的Entry数量减少得多;而且生命周期和Thread相同,如果线程被销毁,对应的ThreadLocalMap也被销毁了。
ThreadLocalMap
ThreadLocalMap内部类里主要使用ThreadLocal的弱引用作为键key,如果ThreadLocal为null的话会删除对应的Entry。
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
网友评论