上网查看了很多篇ThreadLocal的原理的博客,上来都是文字一大堆,费劲看了半天,大脑中也没有一个模型,想着要是能够有一张图明确表示出来ThreadLocal的设计该多好,所以就自己看了源码,画了一张图出来,立刻清晰不少。
根据源码代码理清ThreadLocal结构
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 }
1 ThreadLocalMap getMap(Thread t) { 2 return t.threadLocals; 3 }
1 ThreadLocal.ThreadLocalMap threadLocals = null;
1 private Entry getEntry(ThreadLocal<?> key) { 2 int i = key.threadLocalHashCode & (table.length - 1); 3 Entry e = table[i]; 4 if (e != null && e.get() == key) 5 return e; 6 else 7 return getEntryAfterMiss(key, i, e); 8 }
通过上面的代码可以看出来,在每个线程里面都保存了ThreadLocalMap,而ThreaLocalMap里面又存储了以ThreadLocal为键值的Entry数组。
用一张图来表示更清楚
ThreatLocal的Set步骤
先看ThreadLocal的set方法,我们看一下ThreatLocal具体是怎么操作的
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 createMap(t, value); 8 }
1 void createMap(Thread t, T firstValue) { 2 t.threadLocals = new ThreadLocalMap(this, firstValue); 3 }
通过上面的代码可以看出来ThreadLocal的存储
1、 获取当前线程
2、 获取到当前线程中的ThreadLocalMap
3、 如果获取到的ThreadLocalMap不为null,就以当前ThreadLocal对象为键,以要插入的值为值,ThreadMapLocalMap中。
4、 如果获取的的ThreadLocalMap为null,则创建一个ThreadLocalMap对象
ThreadLocal的Get步骤
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 }
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 createMap(t, value); 9 return value; 10 }
通过上面的代码可以看出来ThreadLocal的Get步骤为
1、 获取当前线程
2、 根据当前线程获取线程中的ThreadLocalMap
3、 如果获取到的ThreadLocalMap不为null,则以当前ThreadLocal为键,获取存储在ThreadLocalMap中的值并返回
4、 如果获取到的ThreadLocalMap为null,则创建一个以当前对象为键的对象,以ThreadLocal设置的初始值为值,存入ThreadLocalMap中,然后返回。
ThreaLocal中的初始值设置
1 protected T initialValue() { 2 return null; 3 }
上面这个initalValue方法是在创建ThreadLocalMap时候的value值的默认初始值,代码中默认返回的是null,我们可以通过自己在代码中自己设计值。