车驰夜幕|面试时被问到ThreadLocal别慌,你要的答案都在这里( 二 )
运行结果:
i:6,count:1i:10,count:1i:3,count:1i:0,count:1i:7,count:1i:11,count:1i:9,count:1i:5,count:1i:8,count:1i:1,count:1i:4,count:1i:2,count:1i:13,count:1i:15,count:1i:14,count:1i:19,count:1i:18,count:1i:17,count:1i:12,count:1i:16,count:1realCount:0
我们可以看到 , 跟之前的例子运行结果差别很大 , 首先现在count全部都是1 , 之前count有8 , 10 , 11 , 12等很多值 。 其次realCount之前是18 , 现在的realCount却是0 。 为什么会造成这样的差异呢?
2.ThreadLocal的工作原理
先看看示例1中的情况
我们可以看到多个线程可以同时访问公共资源count , 当某个线程在执行count++的时候 , 可能其他的线程正好同时也执行count++ 。 但由于多个线程变量count的不可见性 , 会导致另外的线程拿到旧的count值+1 , 这样就出现了realCount预计是20 , 但是实际上是18的数据问题 。
再看看示例2中的情况:
如图所示 , 往大的方向上说 , ThreadLocal会给每一个线程都创建变量的副本 , 保证每个线程访问都是自己的副本 , 相互隔离 。
往小的方向上说 , 每个线程内部都有一个threadLocalMap , 每个threadLocalMap里面都包含了一个entry数组 , 而entry是由threadLocal和数据(这里指的是count)组成的 。 这样一来 , 每个线程都拥有自己专属的变量count 。 示例2中线程1调用calc方法时 , 会先调用的getCount方法 , 由于第一次调用threadLocal.get()返回是空的 , 所以getCount返回值是0 。 这样threadLocal.set(getCount() + 1);就变成了threadLocal.set(0 + 1);它会给线程1中threadLocal的数据值设置成1 。 线程2再调用calc方法 , 同样会先调用getCount方法 , 由于第一次调用threadLocal.get()返回是空的 , 所以getCount返回值也是0 。 这样threadLocal.set(getCount() + 1);会给线程2中threadLocal的数据值也设置成1 。。。。。。 最后每个线程的threadLocal中的数据值都是1 。
还有 , 示例2中打印出来的realCount为什么是0呢?
因为testThreadLocal.getCount()是在主线程中调用的 , 其他的线程改变只会影响自己的副本 , 不会影响原始变量 , count初始值是0 , 所以最后还是0 。
3.ThreadLocal源码解析
在介绍ThreadLocal之前 , 让我们一起先看看Thread类
ThreadLocal.ThreadLocalMap threadLocals = null;
可以看到Thread类中定义了一个叫threadLocals的成员变量 , 它的类型是ThreadLocal.ThreadLocalMap 。 很明显ThreadLocalMap是ThreadLocal的内部类 , 验证了我在图中画的内容 , 每个线程都有一个ThreadLocalMap对象 。
我们再重点看看ThreadLocalMap
static class ThreadLocalMap {static class Entry extends WeakReference> {Object value;Entry(ThreadLocal> k, Object v) {super(k);value = http://kandian.youth.cn/index/v;}}private static final int INITIAL_CAPACITY = 16;private Entry[] table;private int size = 0;private int threshold; // Default to 0private void setThreshold(int len) {threshold = len * 2 / 3;}........省略}
由于该方法太长了 , 我在这里省略了部分内容 。 从以上代码可以看到ThreadLocalMap里面包含了一个叫table的数组 , 它的类型是Entry , Entry是WeakReference(弱引用)的子类 , Entry又包含了 ThreadLocal变量 和Object的value, 其中ThreadLocal变量做为WeakReference的referent 。
- 小鹰说科技|美军警告:别想分割封锁我们,美火速增兵叙利亚!大批装甲车驰援
- 通过率只有3%的面试还难,湖畔大学的学员答辩都在讨论什么?
- 上观新闻|夜幕下的南京路步行街东拓段,灯光璀璨,景色更加迷人
- 柚子在野区|【当当与您早知道】月亮不“孤单”
- 车驰夜幕|美国GPS卫星精度0.4米,俄卫星的精度1.2米,中国北斗呢?
- 车驰夜幕|联合国向你发来活动邀请:与全球尖端人士探讨关注自然的真谛
- 陕西省教育厅|定了!2020年教师资格证笔试、面试时间公布
- 车驰夜幕|简单聊聊处理器的核显
- 模范爸爸|「干货满满」1.5w字初中级前端面试复习总结
- 澎湃新闻|非全日制研究生通过面试后被取消资格?官方:前期审核失误