1.Threadlocal是什么?
ThreadLocal提供了线程的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离。
2.目的是什么?
ThreadLocal设计的目的就是为了能够在当前线程中有属于自己的变量,并不是为了解决并发或者共享变量的问题。很多同学在初学的时候会误解
3.作用?
举个例子:像我们学习jdbc的时候,连接数据库。数据库连接池的连接怎么管理呢??我们交由ThreadLocal来进行管理。为什么交给它来管理呢??ThreadLocal能够实现当前线程的操作都是用同一个Connection,保证了事务
4.用法?
主要方法如下:都依赖于ThreadLocal.ThreadLocalMap内部类。
//获取值
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();
}
//初始化
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;
}
//设置值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//获取线程关联的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//创建ThreadLocalMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocal.ThreadLocalMap内部类
ThreadLocal.ThreadLocalMap内部类,维护着每个线程自己的多个ThreadLocal变量, key为当前的threadLocal实例(ThreadLocal本身不存值,只是引用),value为设置的值 (值存放在ThreadLocal.ThreadLocalMap.Entry实例中)。关键定义如下:
static class ThreadLocalMap {
//存储数据的数组
private Entry[] table;
//获取Entry,key的类型为ThreadLocal
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
}
ThreadLocal.ThreadLocalMap.Entry内部类
ThreadLocal.ThreadLocalMap.Entry内部类,是存储数据的实际数据结构,继承WeakReference,因此是个弱引用,当虚拟机垃圾回收时,无论内存是否足够,都会被回收。
static class Entry extends WeakReference<ThreadLocal<?>> {
/ The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
5.原理?
-
1.每个Thread维护着一个ThreadLocalMap的引用
-
2.ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
-
3.调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象
-
4.调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象
-
5.ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。
6.注意点:
使用ThreadLocal要注意内存泄露,使用完后,要主动调用remove()方法。原因:
- Entry的key是个WeakReference弱引用的ThreadLocal对象,会被垃圾回收,回收后,key会变为null,但value还存在,而又无法通过已经变为null的key索引到value,因此value所在内存便无法使用,又无法回收,导致内存泄露。
- ThreadLocalMap(即位于Thread中的变量)threadLocals本身的生命周期与线程一致,即使ThreadLocal本身弱引用已经回收,但value还存在于ThreadLocalMap中的Entry中,导致内存泄露。
ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。
想要避免内存泄露就要手动remove()掉!