ThreadLocal原理

首先要了解ThreadLocal的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main { 

private static ThreadLocal<Integer> value = new ThreadLocal<Integer>();

public static void main(String[] args) throws InterruptedException{
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0; i <= 10; i++) {
exec.execute(new Runnable() {
@Override
public void run() {
value.set(5);
System.out.println(value.get());
}
});
}
TimeUnit.SECONDS.sleep(5);
exec.shutdownNow();
}
}

问题

  1. ThreadLocal为什么一般要声明为static的
  2. ThreadLocal是如何实现的。

1. ThreadLocal为什么一般要声明为static的

这和ThreadLocal的语义有关

ThreadLocal指的是一个变量属于一个Thread

而如果是实例成员的话, 语义则变为, 一个变量不仅仅属于一个线程, 还属于一个对象,

因为要求只属于某一个线程, 所以最好指定为static的, 但即使是static的, 也并不是只属于某一线程, 还属于某一class

2. ThreadLocal是如何实现的

线程在Java中也是一个对象, 对象的实例成员是属于对象的, 所以, 如果将一个变量保存成线程的实例成员就可以实现线程本地变量。实际上也是如此

  1. Thread有一个ThreadLocalMap成员用来保存线程本地变量
  2. ThreadLocalMap是一个Map, Key是ThreadLocal, Value是ThreadLocal中保存的值
  3. 当调用ThreadLocal的set方法时, 实际上是先得到ThreadLocalMap对象, 再以该ThreadLocal为key, 以value为值保存到ThreadLocalMap中去。

    1
    2
    3
    4
    5
    6
    7
    8
    public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
    map.set(this, value);
    else
    createMap(t, value);
    }
  4. 当调用ThreadLocal的get方法时, 实际上是先得到ThreadLocalMap对象, 再以该ThreadLocal为key, 去取值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null)
    return (T)e.value;
    }
    return setInitialValue();
    }

参考

  1. 理解Java中的ThreadLocal
  2. Why should Java ThreadLocal variables be static