ThreadLocal一般被称为线程池本地变量或线程本地存储。起作用是为“当前线程”提供一个临时持有和传递对象的方法。
由同一个线程锁执行的代码,只要持有同一个ThreadLocal对象的引用,就都能访问到与当前线程绑定的同一个数据对象。
ThreadLocal的内部声明一个自动定义的ThreadLocalMap。它以当前线程对象的引用为key,将希望保存赫尔传递的数据对象存储在这个Map当中。以这样一种方式来为每一个线程分别保存一个值。
我们先了解下它里面基础方法:
get() :获取到当前线程的设置值
setInitialValue():设置值
set(T value):往当前线程写入值
remove():当前线程的值
首先我们看一下其方法对应的源码
//初始化值为null
protected T initialValue() {
return null;
}
//设置ThreadLocalMap对象的值,或者创建ThreadLocalMap对象
private T setInitialValue() {
T value = initialValue();//默认为null值
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
get方法源码
//获取当前线程的值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//获取到当前线程ThreadLocalMap对象不为空。则返回其值。否则初始化该对象值。
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);
else
createMap(t, value);
}
remove方法:
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
使用ThreadLocal需要注意的问题:
1、可能会数据获取错误。
2、内存泄漏问题。
实例代码:
public class ThreadLocalTest1 {
public static void main(String[] args) {
ThreadLocal<String> threadLocal = new ThreadLocal<String>();
ExecutorService cachedPool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 20; i++) {
cachedPool.execute(() -> {
//如果注释该行货到的值全部为null
threadLocal.set(Thread.currentThread().getName());
try {
System.out.println(threadLocal.get());
} finally {
//如果不去释放,可能或获取到原先该线程设置的值。在线程多的情况下会造成内存泄漏
threadLocal.remove();
}
});
}
cachedPool.shutdown();
}
}