1.什么是ThreadLocal
ThreadLocal顾名思义是线程局部变量。这种变量和普通的变量不同,这种变量在每个线程中通过get和set方法访问, 每个线程有自己独立的变量副本。线程局部变量不存在多个线程同时对同一个变量的操作,所以不会有线程安全问题。
2.ThreadLocal变量的使用
public class ThreadLocalDemo {
private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
// 初始化局部变量的值
@Override
protected Integer initialValue() {
return new Integer(0);
}
};
public Integer getNext() {
Integer value = threadLocal.get();
value++;
threadLocal.set(value);
return value;
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
final ThreadLocalDemo demo = new ThreadLocalDemo();
executor.execute(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ": " + demo.getNext());
}
}
});
executor.execute(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ": " + demo.getNext());
}
}
});
}
}
3.ThreadLocal原理
ThreadLocal类中有一个ThreadLoalMap静态内部类,ThreadLoalMap中又有一个Entry静态内部类,代表真实的键值对,其中以ThreadLocal实例为key,要保存在的值为value,Entry类继承了WeakReference,以便于当key为null时加快垃圾回收。ThreadLocal的原理主要看懂get(),set()和initialValue()三个方法就可以了。下来我们来看看源代码的实现:
public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 获得和该线程关联的ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 如果map不为空
if (map != null) {
// 获得以此ThreadLocal为key的键值对
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
// 返回对应键的值
return (T)e.value;
}
// 为空,则调用初始化方法
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
// 每个线程类中引用了一个ThreadLocalMap类型的变量
// 返回当前线程绑定的threadLocals变量
return t.threadLocals;
}
private T setInitialValue() {
// 如果initialValue方法进行初始化
// 如果子类复写了该方法,调用子类的方法,否则返回null
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
// 如果map不为空则设值
if (map != null)
map.set(this, value);
else
// 否则创建一个新的map
createMap(t, value);
return value;
}
protected T initialValue() {
// 该方法被子类复写
return null;
}
void createMap(Thread t, T firstValue) {
// 以当前线程和值构造新的ThreadLocalMap对象
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}