线程1的if代码块要执行的话,那么flag.get()的值必须是false;同理线程2的if代码块要执行的话,flag.get()的值必须是true。也就是说线程1要得到线程2对flag变量操作的值,线程2要得到线程1操作的值。最终没有任何结果输出,说明两个线程没有得到对方修改的内容。
有些小伙伴就说了,各自线程得不到对方操作的内容不是很正常吗?这就是可见性问题啊。确实,由于共享数据存在可见性问题,线程间的数据不能得到很好的同步,也会出现上述场景。那我设计了如下代码,证明了:即使有可见性问题,仍然存在一个线程读取到其它线程操作内容的情况。
因此,我们可以确定ThreadLocal的数据是实现线程隔离的,而且它的目的就是让各个线程之间不可见。
2.1 首先,ThreadLocal对象只给我们提供了三个方法,set、get和remove,那接下来对这三个方法分析一下。
2.2 set方法,赋值是将数据保存到各个线程的ThreadLocalMap中,从而实现线程隔离。
2.3 ThreadLocalMap的set方法实现——ThreadLocal对象为什么要重新定义threadLocalHashCode
2.4 get方法比较简单
2.5 remove()方法——防止内存泄露
网上都说ThreadLocal存在内存泄露,这到底是怎么回事呢?对于一个ThreadLocal来说,它是作为key放在ThreadLocalMap中的,当这个ThreadLocal对象结束了生命,那么它应该被回收。但由于ThreadLocalMap是线程属性,生命周期和线程一样长;线程还未结束时ThreadLocalMap自然有ThreadLocal对象的引用,ThreadLocal也就无法被回收了。于是,开发者将ThreadLocal和ThreadLocalMap之间的引用改为弱引用,Entry不再是一般的键值对,而只有一个value属性,key通过一种弱引用形式表现。这样当ThreadLocal没有了强引用,只有ThreadLocalMap的弱引用,ThreadLocal会被回收。
但是这边又出现了一个问题,虽然Entry的key使用了弱引用,ThreadLocal对象可以被回收。但是Entry的value再也无法通过key访问了,无法回收,value还是存在内存泄露。所以一般在使用ThreadLocal结束后,要调用remove方法,去除key的引用,同时将value值置为null。