类结构:
ThreadLocal
类中有个ThreadLocalMap
内部静态类。内部静态类和外部类,可以单独存在,创建各自不会触发对方的初始化。Entry
又是ThreadLocalMap
的内部静态类,是虚引用的子类,意味着Entry
对ThreadLocal
的引用是弱引用,ThreadLocal
对象的GC和Entry
对象没有关系。
class ThreadLocal{
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}}
通过ThreadLocal
类中的get
,set
方法的分析,方法中操作的map是从Thread
类中获取的,ThreadLocal
只是map中Entry
对象中的key
。
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();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
为啥是这里使用的弱引用?
ThreadLocal<String> aa = new ThreadLocal<>();
aa.set("dfd");
String s = aa.get();
aa.remove();
举个简单使用ThreadLocal
的例子,在执行set
的时候,会在当前线程中创建一个ThreadLocalMap
实例,Entry
(ThreadLocal
实例 -> "dfd")
这时候ThreadLocal
的实例会被两个地方引用:
-
aa
这个变量(强引用) -
Entry
(弱引用)
代码执行完了,第一个引用就可以GC
了,但是第二个Entry
中的引用不会消失,如果是强引用,ThreadLocal
就不会被GC
,会产生内存泄漏。
当Entry中的key- >ThreadLocal 被GC
了,那么Entry
中的value
就没有意义存在了。这时候Thread->ThreadLocalMap->Entry->value
的强引用关系还在,虽然已经获取不到value
了,但是也不会被GC
,所以需要手动remove
去释放value
这块儿内存。
一般多线程如何使用?
一般在多线程都会使用ThreadLocal
的时候,ThreadLocal
可以设置为静态变量,jvm唯一实例,因为每个线程会有自己的map,ThreadLocal
只是个key,不会影响正常使用,还减少了ThreadLocal实例的创建。
为啥ThreadLocalMap是内部静态类?
因为内部静态类在创建,用的时候不用依赖外部类的实例。因为这个特性,可以用内部静态类来实现外部类的单例。
子类InheritableThreadLocal
可以直接创建ThreadLocalMap
类的实例而不用通过ThreadLocal
的实例获取。
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
感觉从代码的角度来说ThreadLocalMap
可以单独出来单独写一个类,这样梳理的时候比较简单。从逻辑的角度来说ThreadLocal
是对外的线程本地概念的抽象,ThreadLocalMap
是实现的内部逻辑,所以内部类比较合适。
网友评论