ThreadLocal的源码分析
2016-06-14 13:41
302 查看
概序
如果你还不知道ThreadLocal是什么东西,请看上一篇 ThreadLocal的快速入门这篇将会讲到ThreadLocal的一些api,然后从源码分析ThreadLocal的工作原理,关于ThreadLocal的使用场景比较少,比如Loop、ActivityThread、ActivityManagerService
ThreadLocal的4个常用api
initialValue() :返回此线程局部变量的当前线程的“初始值”。get():返回此线程局部变量的当前线程副本中的值。
set():返回此线程局部变量的当前线程副本中的值。
remove():移除此线程局部变量当前线程的值。
使用ThreadLocal最重要是了解set()方法和get()方法
set():
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
从源码中可以看出,set方法首先是获取当前线程,然后将当前线程传给getMap()方法,返回一个ThreadLocalMap对象
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
getMap()方法调用线程的threadLocals,通过查看Thread类发现默认为null,没有做实现,所以会调用createMap()方法,
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
createMap方法中通过当前线程和要设置的值value new了一个ThreadLocalMap,并且将new的实例赋值给当前线程的threadLocals。
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }
从源码可以看出通过key和value构造一个Entry对象,并且放到table数组里面。这里的table比较重要,后面的get方法也会用到。这里我们已经了解了set方法的工作原理
get():
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
get()方法首先是获取当前的线程,然后调用getMap(t);通过当前线程获取值
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
getMap()方法通过当前线程获取threadLocals,由于之前调用了set方法,所以此时的threadLocals不会为null。在threadLocals不为null的情况下,调用getEntry()方法获取值,如果值不为null的情况下,返回;如果上面条件不满足的话,调用setInitialValue()方法,
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
他会调用initialValue()进行初始化一个value,然后和set方法类似的了。到这里get方法的实现原理我们也了解了。
最后再看看另外两个api
initialValue():线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。 这点可以从get方法的源码中可以看出
remove(): 如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法,看如下代码。
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
/** * Remove the entry for key. */ private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } }
OK,到这里,ThreadLocal的分析将全部完成了。
相关文章推荐
- 618必须要占的便宜,抢一款适合你的智能穿戴产品
- asp.net webpage
- H-Index
- erlang 进程的 hibernate
- 怎样用NiceLabel隐藏条码下的数据?
- 7,4汉明码及8,4扩展汉明码的实现
- opencv 图片的离散傅里叶变换DFT
- 贝叶斯分类器-----数据挖掘
- 第十、十一周课后实践(1)
- Arduino 硬件开发 教程收集
- 字符串
- nginx改tengine,gitlab重装操作步骤
- 保障分布式系统的稳定性(一):流量控制
- Ubuntu12编译openjdk7
- Andriod中应用开机自启动的问题
- Linux下python升级步骤
- Factorial Trailing Zeroes - Javacript
- poj之旅——1222
- 钱海支付笔试
- NPF驱动核心指南