ThreadLocal专题(二)— 数据仓库机制

共图社大白 大白共图社  

 

 

思维一,构建Thread数据仓库机制

今天介绍的角色是线程的数据仓库群和仓库管理员:

 

1.数据仓库管理人员:ThreadLocalMap

             

这个仓库管理员维护的属性:Entry数组 table,table数组的大小。

仓库管理员的核心行为如图所示:

             

图中反馈的信息可以知道:仓库管理员维护着仓库群table,而getEntry,set,remove方法表示对table的行为:仓库内物品的获取,物品的存放,物品的清除。

 

 

2.数据仓库:Entry

             

仓库管理员维护的数据仓库群table数组的元素类型就是Entry,这个类是个特殊的类,这里不做进一步的剖析,会在以后文章内单独提出来。

数据仓库的角色Entry维护这一个属性value,没有其他行为方法,所以仓库内存放的物品只有一个,即value,是个object类型——可以放入java体系中的任何引用类型。

因此,ThreadLocal的数据仓库可以放入任何类型的数据。

 

 

 

线程的数据仓库机制

线程维护这数据仓库的管理员角色,而且还有两个管理员threadLocals和inheritableThreadLocals

            

这里我们只谈threadLocals这一个属性,我们上面已经分析,threadLocals是一个数据仓库群管理员,管理着仓库群tables,方法有:set,getEntry,remove等。字段threadLocals在线程类中的访问权限是默认修饰符,所以同一个包的类ThreadLocal可以访问。

所以长工角色虽然是个打工的人,但是真正干事的还是仓库群管理员ThreadLocalMap,因为长工的搬运工作都是委托给管理人员来施行的,他只需要在仓库外面等待,ThreadLocalMap类的get方法在ThreadLocal的get方法中,如下图。

            

 

其他委托方式也和get类似,如下两个图。

            

            

 

 

 

线程的数据仓库继承机制

Thread的继承机制,大家可能还没碰到过,但是在java体系中却十分重要,不过这里的继承机制不是java中的类继承。这里的继承是指父子线程的属性继承以及数据仓库群的继承。

 

子线程Thread被创建时会调用init()方法,这个方法是在父线程中运行,其中一行代码

            

所以,parent是当前线程(父线程)的引用,所以父子线程的属性继承传递发生在init()方法内,下图是线程组,守护线程,线程优先级等属性的继承代码。

            

 

数据仓库的继承代码如下图,inheritableThreadLocals是用于数据仓库继承机制的属性,ThreadLocalMap的引用。

            

图中代码显示,如果父线程inheritableThreadLocals属性不为空,则会创建一个新的ThreadLocalMap对象给子线程对象,且管理的仓库群物品和父线程一样。这就是线程的继承机制。

 

 

长工ThreadLocal的工作

所有的线程都是公用一个ThreadLocal对象的,线程通过threadlocal来从线程内部数据仓库群中获取数据,不言而喻,几个线程调用同一个threadlocal返回的是不同数据,同样set存放进去的数据也是使用同一个threadlocal的set方法。还有数据的移除和初始化,如下所示:

1.ThreadLocal.get:长工角色获取数据

2.ThreadLocal:set:长工角色存放数据

3.ThreadLocal:remove:   长工角色移除数据

 

我们已经谈到,仓库的数据存放工作不是由长工角色Thread Local来完成的,而是委托给仓库群的管理员角色Thread LocalMap来执行的,分别对应ThreadLocalMap的方法,如下所示:

1.ThreadLocalMap.getEntry(ThreadLocal<?>key):

2.ThreadLocalMap.set(ThreadLocal<?>key,Object value):

3.ThreadLocalMap.remove(ThreadLocal<?>key);

也就是说ThreadLocal的三个方法get,set,remove都在方法体内调用了ThreadLocalMap的getEntry,set,remove方法,而这个ThreadLocalMap数据管理员角色对象是线程的字段,在ThreadLocal的三种方法中都需要去获取当前线程的ThreadLocalMap对象,代码如下所示:

            

三个方法里面都有这段代码:先获取Thread LocalMap对象,即Thread Local将数据的搬运工作委托给了线程对象的属性ThreadLocalMap。

 

对长工工作的小结:大兄弟角色线程将数据搬运工作委托给threadlocal长工角色,而长工找到属于大兄弟的数据仓库群管理员threadlocalmap,将搬运的工作委托给管理员。

 

 

table中仓库Entry的定位

我们现在已经知道线程对象 的数据放入的是数据仓库table数组中,每个threadlocal对象获取和存放操作是处理table数组中的哪个位置的数据,位置是如何定位的,这个就要涉及到ThreadLocal的其他机制,例如:ThreadLocal对象唯一ID机制,ThreadLocal的get初始化值机制等等。

 

 

上面段落提到数据的搬运工作最后是委托给了ThreadLocalMap这个对象,以get方法为例,底层是管理员角色的getEntry方法在工作,如下图所示:

            

threadLocalHashCode字段属性是ThreadLoca对象唯一ID机制中的ID,表示这个对象的唯一性质,而这个i值也就因为这个threadLocalHashCode的唯一性而具有唯一性。所以可以判断具有唯一性的Threadlocal对象能获得具有唯一性质的i,因此对应的table[i]也就唯一对应到ThreadLocal对象了。

 

对仓库Entry定位的小结:因为ThreadLocal对象的具有唯一性,因此它指向的是线程对象中数据仓库群table中的其中一个数据仓库entry,哪个线程委托threadlocal对象,threadlocal就去哪个线程下的仓库群进行操作。这个小结能够解决对ThreadLocal体系模糊不清的疑问,为什么不同线程调用同一个threadlocal对象的相同方法会获取不一样的数据?为什么不同的线程使用一个threadlocal对象进行set,还能保存两种这样的数据?

 

ThreadLocal数据仓库机制,它不仅仅只涉及到ThreadLocal这一个角色类,它还与Thread角色类强关联一起:数据就是维护在Thread对象中的。而数据存放位置的定位key包括:具有唯一行的ThreadLocal对象+Thread对象。到这里就是我对于ThreadLocal数据仓库机制的分享,感谢阅读,希望能帮助到你,我是大白,我来自共图社,一个持续输出Java好文的平台。

 

                      talk is cheap  ,show you the code and the doc,更多的分享内容请关注我的工作号:大白共图社。公众号会有很多的github开源社区拿来即用项目源码以及相关的文章。欢迎关注。 

                                                                       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

比特科技软件开发工作室

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值