ThreadLocal 源码分析 - 扩容和 get 方法
get 方法
ThreadLocal 中的 get():
Thread t = Thread.currentThread();
get 获取之前,从获取当前的线程对象,因为 ThreadLocal 保存的数据也都是属于当前线程的
getMap(t);
从当前线程中获取 ThreadLocalMap 对象
ThreadLocalMap.Entry e = map.getEntry(this);
从 ThreadLocalMap 中获取 entry,entry 中保存的就是具体的值
在 ThreadLocalMap 的 getEntry 方法中,方法内部首先是将参数的 hash 值与数组大小取模并减一,作为索引位置查询数据,如果找不到对应的数据(数据为空)则自选将索引+1 继续寻找,直到找到为止。因为这种不断的自旋找法,如果使用了大量的 key 的话,数据获取的效率就会很低。
扩容方法
Entry[] oldTab = table;
先拿出旧的数组
int newLen = oldLen * 2;
扩容的新数组为旧数组大小的 2 倍
for (int j = 0; j < oldLen; ++j) { ... }
将老数组的值拷贝到新数组中
setThreshold(newLen);
设置数组新的扩容阈值,阈值为数组长度的三分之二
这里的扩容不像 ArrayList 或者其他线程安全的集合扩容方法,这里没有考虑 modCount,也就是没有考虑到线程不安全的情况,这是因为本来这就是线程的独属的方法,只有一个线程,也就是线程本身才能操作这部分的数据,所以不会存在线程不安全的情况。
总结
ThreadLocals.ThreadLocalMap 和 InheritableThreadLocals.ThreadLocalMap 是线程独有的属性,每个线程的 ThreadLocal 都是隔离的,所以是线程安全的。
当在一个线程中创建另一个线程时,也就存在父子线程的关系,但是子线程的 ThreadLocal 不会和父线程的 ThreadLocal 共享。
版权声明: 本文为 InfoQ 作者【zarmnosaj】的原创文章。
原文链接:【http://xie.infoq.cn/article/6e4857b71f6816c179d1882a9】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论