图解 ThreadLocal

ThreadLocal 以空间换时间来实现线程隔离,解决多线程中相同变量的访问冲突问题,保证了别的线程不会访问到线程内的变量。
图解 ThreadLocal_第1张图片

1.每一个线程对应一个ThreadLocalMap

在使用 ThreadLocal 时(get/set 方法),会为当前线程 Thread 类中的threadLocals创建ThreadLocalMap对象。之后,如果当前线程使用 ThreadLocal 直接获取 Thread 类的threadLocals对象。

源码可见:
①ThreadLocal -> get() -> setInitialValue() -> createMap(t, value)
②ThreadLocal -> set(T value) -> createMap(t, value)

2.ThreadLocal 是如何定位获取数据的

在 ThreadLocalMap 中,使用table[]数组存储数据,ThreadLocal 主要通过threadLocalHashCode计算数组索引,来获取数据。

int i = key.threadLocalHashCode & (table.length - 1);
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);

那么 ThreadLocal 是如何保证threadLocalHashCode的唯一性的(同一个线程下,每一个 ThreadLocal 的threadLocalHashCode都不同)?

主要通过下面这几个字段:

private final int threadLocalHashCode = nextHashCode();

private static AtomicInteger nextHashCode =
    new AtomicInteger();

private static final int HASH_INCREMENT = 0x61c88647;

private static int nextHashCode() {
    return nextHashCode.getAndAdd(HASH_INCREMENT);
}

由于 nextHashCode 是静态变量,会在类加载阶段进行初始化,这就保证了一个线程中nextHashCode 的唯一性。
在创建 ThreadLocal 对象时(new ThreadLocal),会对当前 ThreadLocal 对象的threadLocalHashCode进行初始化,初始化的值就是让nextHashCode自增0x61c88647,并返回赋值给threadLocalHashCode
这样在同一个线程下,每次创建 ThreadLocal 对象时,都会获得不同的threadLocalHashCode值。

  • 对于某一个 ThreadLocal 来讲,他的索引值 i 是确定的,在不同线程之间访问时访问的是不同的 table[] 数组的同一位置即都为 table[i],只不过这个不同线程之间的table是独立的;
  • 对于同一线程的不同 ThreadLocal 来讲,这些 ThreadLocal 实例共享一个table[] 数组,然后每个 ThreadLocal 实例在 table 中的索引 i 是不同的。

你可能感兴趣的:(并发编程,多线程,java,ThreadLocal)