问题引出
今天学习《Java并发编程的艺术》一书第4章中ThreadLocal的问题,书中对ThreadLocal的讲解和使用篇幅较短,于是自己做了一些小实验,过程中遇到了一个问题。问题代码如下:
1 | class Person { |
可以看到,在输出中,对is
引用的ThreadLocalIs
对象中的Integer
类型的value
赋值被成功输出,对ThreadLocal
类型的threadLocal
变量的赋值却丢失了。折腾了很久,才搞明白是怎么回事。
原因
这是因为,ThreadLocal
对象隶属于线程管理,而非对象管理。也就是说,虽然is
对象中声明了一个ThreadLocal
对象,但是对它的赋值操作却是在线程中执行的,也即main
线程中进行的赋值,那么,main
线程中中的ThreadLocalMap
类型的threadLocals
中就会挂载is
对象中的threadLocal
对象。也即,该ThreadLocal
对象属于main
线程,而不属于is
对象。如果将set()
操作放在ThreadLocalIs
类中的run()
方法内执行,那么该ThreadLocal
对象就会挂载在新建它的线程上,也即t
上。
ThreadLocal
关于ThreadLocal的原理源码分析啥的这里就不再赘述,网上有很多优质的博文做了详细的介绍说明。这里给出一些自己的理解总结:
- ThreadLocal,线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构,例如:
ThreadLocal<Person> obj = new ThreadLocal<>(); Person fan = new Person(); obj.set(fan);
代码中,对于该线程中,obj为键,fan对象为值。线程可以根据obj对象(ThreadLocal对象)查找到fan对象(值)。 - 每个线程维护一个ThreadLocalMap,该Map中存放着所有在该线程中注册的ThreadLocal键值对对象。因此,ThreadLocal是线程隔离的,也即线程安全的。