公共类线局域网< T > 扩展对象
ThreadLocal来自JDK1.2,位于Java.lang package中。ThreadLocal可以在线程中提供局部变量。该变量在线程的生命周期中起作用。ThreadLocal也称为线程本地变量/线程本地存储。
实际上,就螺纹锁定而言,它不存储任何内容。真正存储数据的数据集合在每个线程中的线程界面变量中。将提及后续源代码分析!
可以说,ThreadLocal只是一个工具类,是操作每个线程的线程界面的工具。
线路的作用和目的:
与ThreadLocal的同步是解决多线程中数据访问问题的两个想法。前者是数据共享的想法,后者是数据隔离的想法。同时化是改变时间空间的想法,而ThreadLocal是一个可以更改时间的空间。前者仅提供一个变量来允许排队访问和实现序列化的不同线程;后者为每个线程提供了一个变量,因此可以同时访问它而不会相互影响。
ThreadLocal无法替代同步。请注意,ThreadLocal不用于求解对共享对象的多线程访问的问题。ThreadLocal's Set()方法设置为线程的线程界面是线程本身想要存储的对象。其他线程不需要访问它,也无法访问它。每个线程中的threadLocals和值是不同的对象。Threadloocal用于隔离变量,也就是说,ThreadLocal的针对那些不需要共享的属性!
有四种调用ThreadLocal类的主要方法:
线程案例以在线程之间共享线程和数据隔离的数据共享:
结果如下:
首先设置值,然后获取,您可以获取“ main”。然后打开子线程,将其放入子线程中,先获取它,获取空,然后设置值,然后设置值,然后获取它以获取“孩子”。最终,尝试将其放入主线程中,并获得了原始值“ main”,这表明线程局部将变量范围限制为该线程。其他线程无法访问变量。
请注意,由于案例演示未在最后调用删除方法,因此应在实际使用后使用删除方法。该原则将在稍后说!
ThreadLocal类定义了内部类ThreadLocalMap。ThreadLocalMap是一个真正存储数据的容器。实际上,其底层是哈希表。
每个线程用变量类型定义,因此线程之间的线程截图不会彼此干扰。当threadlocal呼叫时调用集合或get方法时,该变量持有的螺纹LOCALMAP会初始化。
ThreadLocal还提供了相关的方法,以获取并设置当前线程螺纹Localmap变量的变量值,该变量等效于工具类。
当在线程方法中使用螺纹局部设置时,将螺纹局部对象添加到线程内的螺纹锁定对象。关键是螺纹局部对象,该值可以是任何类型的任何类型。在某个线程方法中获得threadLocal时,线程局部对象被用作在线程的螺纹界面中获得相应值的键。
ThreadLocal定义了ThreadLocalMap的结构,并提供了操作方法:
每个线程对象都保留用于存储螺纹的本地变量的螺纹localmap参考变量。Key是线程局部对象,值是要存储的数据。
以下是线程,螺纹磁板,螺纹local之间的关系的图表:
ThreadLocal定义了ThreadLocalMap的结构。
ThreadLocalMap也是干草值类型的哈希表,但是ThreadLocalMap并未实现MAP接口。它具有一个表格的表格阵列来存储节点。输入节点用于存储密钥和值数据并继承弱recreference。
通过对螺纹局部对象进行哈希操作,您可以在输入阵列中获取螺纹插座对象的枪管位置,以找到唯一的条目。如果发生哈希冲突,则与hashmap和hashmap和hashtable和hashtable一起采用的“链地址方法”,threadLocalMap使用“线性检测方法”来解决哈希冲突。从总的来说,threadlocalmap并未存储大量数据!关于哈希表的原理和各种求解哈希冲突的方法,您可以阅读本文:数据结构 - 扫描列表(哈希表)和Java代码的实现。
在创建ThreadLocalMap对象时,它初始化了16个内部表数组,具有16个长度。
当设置螺纹局部并且未使用该值时,线程中的螺纹截图对象始终为null。
设置方法由ThreadLocal提供,用于存储数据。步骤如下:
在上面的方法中,如果当前t线的线程界面不是null,则调用另一个专用集方法来存储数据。此方法是螺纹插座的核心方法之一,并且更复杂。它有以下步骤:
threadLocalMap使用==键是否相同。线程localmap解决哈希冲突的方法就是简单地加1或减1(线性检测)以找到下一个相邻位置。阵列的后部向后,下一个位置是阵列的尾部或阵列头,即圆形搜索。
在集合方法中,我们可以找到threadlocalmap ::的哈希算法
int i = key.threadLocalHashCode&(len -1);
因为LEN的长度必须是2的功率,因此可以将上述操作转换为上述,因此ThreadLocalMap的哈希算法也是一个,因为其余数字将小于分区,然后计算出的枪管位置必须位于[0len-1],就在基础数组的索引范围内,它相对简单。
这里的钥匙知道它是螺纹局部对象。此属性取决于名称的名称是对象的哈希值。因此,该值是通过HashCode方法获得的吗?实际上,此属性非常有趣。我们必须转到ThreadLocal源代码!
结合上述属性和方法,我们最终理解:
首次创建ThreadLocal实例时,将加载ThreadLocal类。目前,NexthashCode的初始值为0,然后初始化对象螺纹座式尺寸。创建此类后,将自动调用NexthashCode方法到下一个下一次。值作为其自己的哈希码和NexthashCode对象的值增加,显然是下一个的哈希尺寸值threadlocal实例。
也就是说,在创建实例作为自己的哈希码时,每个螺纹局部实例都使用nexthashcode值,然后将newhashCode值添加到哈希码中,将其作为下一个线程列表实例。
这是转换为十进制的十六进制的数量为1640531527。实际上,此哈希值的选择与fibona销售听力方法和黄金有关(https://wwwww.javaspects.eu/archives.eu/archive/问题164.html),目的是使Hash代码更均匀地分布在N -Next -side 2的数组中。
对于不同的线程,每次获得变量值时,都会从线程内的线程界面获得。其他线程无法获得当前线程的值,形成变量隔离,而不会彼此干扰。这些步骤如下:
在此步骤中,可能是线程销售是空的,或者E找不到E.然后调用SetinItalValue方法,为当前的ThreadLocal对象设置条目,然后返回值。
根据Key,ThreadLocalMap的内部方法尝试获取相应的输入节点。这些步骤如下:
ThreadLocal的方法用于设置和返回初始值。当Get方法找不到密钥的相应节点时,将调用此方法!
有以下几个步骤:
2.4.2.1初始值方法当找不到GET方法时,将调用setInitialValue方法。此方法将调用初始值方法,并将默认值返回为null。初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始初始报价。
setInitialValue将基于当前的螺纹局部对象,并且初始值的返回值是存储节点并返回值的值的值。
2.4.2.2默认初始值情况首先是所有基本知识。Java中的参考文献简介:Java中强,软,虚弱和虚拟对象引用的详细说明和案例演示。
根据上面的源代码,我们知道,在存储新节点时,在输入节点的构造函数中,它不是直接使用threadlocal对象作为键,而是使用threadlocal对象包装的弱参考对象作为键。弱参考场关联,也从弱参考场中获得获得密钥。
为什么使用弱引用的螺纹局部对象作为键?因为如果条目直接与threadlocal对象的共同属性直接关联,也就是说,键是一个很强的参考。然后,当引用了threadlocal对象的总体变量时,因为在ThreadLocalMap中对此threadLocal对象的关键引用,那么此螺纹插座对象将无法回收,但是目前我们无法再访问并使用此对象。导致key的内存泄漏。
因此,将螺纹局部对象作为钥匙打包为键。在这种方式上,当清除外部线程对象的强引用时,弱参考键存储在threadlocalmap中。可以自动清除weat threadlocal cocterlocal对象。
但是,此时仍将导致内存泄漏,但目前是值或输入的内存泄漏。
我们知道价值是一个有力的参考,这导致了一个问题。如果此弱引号是回收的并变为null,如果在连续运行螺纹lotepal方法之前设置了螺纹锁定方法的线程,那么它的threadlocalmap始终存在,那么内部输入节点始终存在。时间,无法通过键访问(因为键已回收为空),并且此时发生内存泄漏。
因此,最安全的方法是删除无效的条目。
我们可以在集合的源代码中看到,并获得方法,当遍历条目的钥匙为null时,目前将清除条目和值,以便可以解决某些内存泄漏问题。但这不是绝对的。它可能不会传播到钥匙到null的输入。此方法是一种被动删除,无法立即删除。
ThreadLocal还具有一个删除方法,该方法可以删除与此螺纹插座对象相对应的条目。实际上,在使用threadlocal的数据之后,从逻辑上讲,此时的条目是无效的数据,因此请在删除删除该方法一次输入。这样,我们可以手动删除完成的条目,从根本上消除了内存泄漏的问题。
因此,培养良好的编程习惯非常重要。使用ThreadLocal的数据后,您必须记住一次调用删除方法。
总结:
应用: