一图流

ThreadLocal - 图2

  • 注意下同一个线程要使用同一份引用,不要瞎 new
  • 及时 remove()

Thread ThreadLocalMap ThreadLocal 关系

  1. Thread 有一个成员变量 ThreadLocal.ThreadLocalMap threadLocals = null;
  2. ThreadLocalMapThreadLocal 的静态内部类
    1. ThreadLocalMap 存储的是弱引用类型的 ThreadLocal
    2. key 为 ThreadLocal 对象 , value 为 对应的值
      1. public class ThreadLocal {
      2. // other
      3. static class ThreadLocalMap {
      4. // other
      5. static class Entry extends WeakReference<ThreadLocal<?>> {
      6. Object value;
      7. Entry(ThreadLocal<?> k, Object v) {
      8. super(k);
      9. value = v;
      10. }
      11. }
      12. }
      13. }
  • 图示

image.png

注意点

  • ThreadLocalMap 中 对 Entry 数组的管理不是类似 HashMap 的拉链法
    • 而是 线性探测法

重要方法

T initialValue()

  • 仅仅被 ThreadLocal#get() 调用,用于 延迟加载

    1. protected T initialValue() {
    2. return null;
  • 一般都是要 重写 的,如果不需要初始值,可以不用

T get()

  • 自带 延迟加载
  • 如果 Thread#currentThread().threadlocals 中是否存在调用 get()ThreadLocal 对象的元素
    • 有则返回对应元素的值
    • 没有则调用 setInitialValue() ,设置 thisThread 且返回
      1. public T get() {
      2. Thread t = Thread.currentThread();
      3. ThreadLocalMap map = getMap(t);
      4. if (map != null) {
      5. ThreadLocalMap.Entry e = map.getEntry(this);
      6. if (e != null) {
      7. @SuppressWarnings("unchecked")
      8. T result = (T)e.value;
      9. return result;
      10. }
      11. }
      12. return setInitialValue();
      13. }

setInitialValue

  • 将 调用 get()ThreadLocal 对象的元素存储进当前线程的 threadlocals
    1. private T setInitialValue() {
    2. T value = initialValue();
    3. Thread t = Thread.currentThread();
    4. ThreadLocalMap map = getMap(t);
    5. if (map != null)
    6. map.set(this, value);
    7. else
    8. // 对应 Thread.currentThread.threadlocals 一开始为 null;
    9. createMap(t, value);
    10. return value;
    11. }

remove()

  • 将 调用 get()ThreadLocal 对象的元素从当前线程的 threadlocals 中删除
    1. public void remove() {
    2. ThreadLocalMap m = getMap(Thread.currentThread());
    3. if (m != null)
    4. m.remove(this);
    5. }

set(T value)

  • 将 调用 get()ThreadLocal 对象的元素存储进当前线程的 threadlocals
    1. public void set(T value) {
    2. Thread t = Thread.currentThread();
    3. ThreadLocalMap map = getMap(t);
    4. if (map != null)
    5. map.set(this, value);
    6. else
    7. // 对应 Thread.currentThread.threadlocals 一开始为 null;
    8. createMap(t, value);
    9. }