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


作者:空白

alt 思维一,构建Thread数据仓库机制 今天介绍的角色是线程的数据仓库群和仓库管理员: 1.数据仓库管理人员:ThreadLocalMap alt 这个仓库管理员维护的属性:Entry数组 table,table数组的大小。 仓库管理员的核心行为如图所示: alt 图中反馈的信息可以知道:仓库管理员维护着仓库群table,而getEntry,set,remove方法表示对table的行为:仓库内物品的获取,物品的存放,物品的清除。

2.数据仓库:Entry alt 仓库管理员维护的数据仓库群table数组的元素类型就是Entry,这个类是个特殊的类,这里不做进一步的剖析,会在以后文章内单独提出来。 数据仓库的角色Entry维护这一个属性value,没有其他行为方法,所以仓库内存放的物品只有一个,即value,是个object类型——可以放入java体系中的任何引用类型。 因此,ThreadLocal的数据仓库可以放入任何类型的数据。

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

这里我们只谈threadLocals这一个属性,我们上面已经分析,threadLocals是一个数据仓库群管理员,管理着仓库群tables,方法有:set,getEntry,remove等。字段threadLocals在线程类中的访问权限是默认修饰符,所以同一个包的类ThreadLocal可以访问。 所以长工角色虽然是个打工的人,但是真正干事的还是仓库群管理员ThreadLocalMap,因为长工的搬运工作都是委托给管理人员来施行的,他只需要在仓库外面等待,ThreadLocalMap类的get方法在ThreadLocal的get方法中,如下图。 alt

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

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

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

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

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

图中代码显示,如果父线程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对象,代码如下所示: alt

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

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

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

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

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好文的平台。

扫码或搜索:前沿科技
发送 290992
即可立即永久解锁本站全部文章