ThreadLocal不是一个Thread,而是一个Thread-local variable(线程本地变量),我这里就暂且翻译成线程本地变量,当然你也可以叫线程局部变量,当使用ThreadLocal维护变量的时候,ThreadLocal会为每个使用该变量的线程提供一个独立的副本,每个线程都可以修改该副本,而不会影响到其它的副本。
ThreadLocal
构造方法
构造函数,空的,什么事情都没有做
public ThreadLocal() {
}
初始化方法
初始化方法,是一个protected方法,显然是为了让子类覆盖的,该方法不会在ThreadLocal创建的时候调用,而是会在第一次调用get方法时执行,并且只会执行一次,并且返回要维护的线程本地变量或null。
protected T initialValue() {
return null;
}
get方法
返回线程本地变量在当前线程的副本拷贝
public T get() {
//查询ThreadLocalMap是否已经保存了当前线程的线程本地变量
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
//如果ThreadLocalMap存在当前线程的线程本地变量就返回
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//没有就调用初始化方法并保存到ThreadLocalMap
return setInitialValue();
}
private T setInitialValue() {
//调用初始化方法
T value = initialValue();
//保存线程局部变量到ThreadLocalMap
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
set方法
保存线程本地变量到ThreadLocalMap
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方法
从ThreadLocalMap删除当前线程的线程本地变量
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocalMap
在学习ThreadLocal的api的时候一直出现ThreadLocalMap,它与ThreadLocal什么关系?
Thread、ThreadLocalMap和ThreadLocal什么关系
1.每个Thread对象都持有一个ThreadLocalMap成员变量
class Thread implements Runnable {
//省略 ......
ThreadLocal.ThreadLocalMap threadLocals = null;
//省略 ......
}
2.每个ThreadLocalMap包含多个ThreadLocal键值对
3.也就是说每个Thread可以有多个ThreadLocal
ThreadLocal会不会存在内存泄漏问题?
会,为什么?
static class ThreadLocalMap {
//1.ThreadLocalMap的每个Entry都是一个对key的弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
//2.每个Entry又都包含了一个对value的强引用
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
正常情况下,当线程终止,保存ThreadLocal里的线程本地变量就会被垃圾回收,因为没有任何强引用了;但是如果线程不终止,比如线程池中的线程,那么就不会被正常回收。
怎么解决?
如果不用的时候就调用remove清除掉就可以了。
class SimpleDateFormatTest {
//线程池
static ExecutorService threadPool = Executors.newFixedThreadPool(10);
//ThreadLocal
static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>(){
//初始化
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static void main(String[] args) {
for (int i=0; i<100; i++){
int fi = i;
threadPool.submit(new Runnable() {
@Override
public void run() {
Date date = new Date(1000 * fi);
//获取
String format = dateFormatThreadLocal.get().format(date);
System.out.println(format);
//清除
dateFormatThreadLocal.remove();
}
});
}
threadPool.shutdown();
}
}