概述
以下内容来源于源码注释
ThreadLocal类提供了线程局部 (thread-local) 变量。这些变量与普通变量不同,每个线程都可以通过其 get 或 set方法来访问自己的独立初始化的变量副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
类图
内容提炼:
1、Thread 类有维护了一个属性变量 threadLocals (ThreadLocal.ThreadLocalMap threadLocals = null),也就是说每个线程有都一个自己的 ThreadLocalMap ,所以每个线程往这个 ThreadLocal 中读写隔离的,并且是互相不会影响的 。
2、ThreadLocalMap 类是 ThreadLocal 的静态内部类
3、ThreadLocalMap 维护了一个 Entry 数组,Entry 的 key 是 ThreadLocal 对象,value 是存入的对象,所以一个 ThreadLocal 只能存储一个Object对象,如果需要存储多个Object对象那么就需要多个 ThreadLocal
4、Entry 的 key 引用 ThreadLocal 是弱引用
源码分析
成员变量:
/**
* 初始容量 —— 必须是2的冥
*/
private static final int INITIAL_CAPACITY = 16;
/**
* 存放数据的table,Entry类的定义在下面分析
* 同样,数组长度必须是2的冥。
*/
private Entry[] table;
/**
* 数组里面entrys的个数,可以用于判断table当前使用量是否超过负因子。
*/
private int size = 0;
/**
* 进行扩容的阈值,表使用量大于它的时候进行扩容。
*/
private int threshold; // Default to 0
/**
* 定义为长度的2/3
*/
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
内部类ThreadLocalMap :
public class ThreadLocal<T> {
// ThreadLocalMap 是 ThreadLocal 的静态内部类
static class ThreadLocalMap {
// Entry 是 ThreadLocalMap 的静态内部类
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
// Entry 的 key 是 ThreadLocal 对象,value 是关联的数据对象
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
// ThreadLocalMap 维护了一个 Entry 数组,
private Entry[] table;
}
}
内部类:Entry
/**
* Entry继承WeakReference,并且用ThreadLocal作为key.如果key为null
* (entry.get() == null)表示key不再被引用,表示ThreadLocal对象被回收
* 因此这时候entry也可以从table从清除。
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
WeakReference是什么?
强引用(StrongReference):被强引用关联的对象不会被回收
软引用(SoftReference):被软引用关联的对象只有在内存不够的情况下才会被回收
弱引用(WeakReference):被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前
WeakReference 是 Java 语言规范中为了区别直接的对象引用(程序中通过构造函数声明出来的对象引用)而定义的另外一种引用关系。WeakReference 标志性的特点是:reference 实例不会影响到被引用对象的 GC 回收行为(即只要对象被除 WeakReference 对象之外所有的对象解除引用后,该对象便可以被 GC 回收),只不过在被对象回收之后,reference 实例想获得被应用的对象时程序会返回 null。
其他常用方法后续学习补充~