zl程序教程

您现在的位置是:首页 >  工具

当前栏目

ThreadLocal源码浅析

源码 浅析 ThreadLocal
2023-09-14 08:57:28 时间
ThreadLocal不是一个具体的线程。它是一个线程内部的数据存储类,通过它可以再指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说则无法获取到数据。   ThreadLocal之所以有这么神奇的效果,是因为不同线程访问同一个ThreadLocal的get方法,ThreadLocal内部会将各自线程的引用当做table数组的一个值存在,然后从数组中根据当前ThreadLocal的reference去查找出相应的value。这就是为什么通过ThreadLocal可以再不同线程中维护一套数据的副本并且彼此互不干扰。   在java中ThreadLocal以Map的形式存储数据(ThreadLocal对象为 key  数值为value)。在Android中做了些改动,在Thread-Local的add方法中,可以看到它会把ThradLocal对象(key)和相对应的value放在table数组连续的位置中。 也就是table被设计为下标为0,2,4...2n的位置存放key,而1,3,5...(2n +1 )的位置存放value。
void add(ThreadLocal ? key, Object value) {

 for (int index = key .hash mask ;; index = next(index )) {

 Object k = table[ index];

 if (k == null) {

 table[ index] = key. reference;

 table[ index + 1] = value;

 return;

类中最重要的两个方法是get(),set()。下面开始分析set()源码。

Thread currentThread = Thread.currentThread(); Values values = values( currentThread); if (values == null) { values = initializeValues(currentThread ); values.put( this, value ); 首先获取当前线程对象currentThread,然后执行values(currentThread)方法。源码如下:
     在values (currentThread )中返回了currentThread .localValues。跟进Thread的源码可以发现:这个currentThread .localValues其实就是ThreadLocal.Values  localValues 。Values 是ThreadLocal中的一个静态内部类。此时获取到返回的Values对象。      接下来进行判空操作,如果返回的values为空,那么再次实例化currentThread。跟进initializeValue-s(currentThread)可以发现
Values initializeValues(Thread current) {

 return current .localValues = new Values();

new Values()的实例化过程:

 Values() {

 initializeTable( INITIAL_SIZE);//INITIAL_SIZE 默认值16

 this.size = 0;

 this.tombstones = 0;

 private void initializeTable( int capacity ) {

 this.table = new Object[capacity * 2];

 this.mask = table .length - 1;

 this.clean = 0;

 this.maximumLoad = capacity * 2 / 3; // 2/3

此时可以确保有了Values的一个实例,接下来就可以执行values .put(this, value ),跟进put方法
void put(ThreadLocal ? key, Object value) {

 cleanUp();

 // Keep track of first tombstone. Thats where we want to go back

 // and add an entry if necessary.

 int firstTombstone = -1;

 for (int index = key .hash mask ;; index = next(index )) {

 Object k = table[ index];

 if (k == key .reference ) {

 // Replace existing entry.

 table[ index + 1] = value;

 return;

 if (k == null) {

 if (firstTombstone == -1) {

 // Fill in null slot.

 table[ index] = key.reference ;

 table[ index + 1] = value;

 size++;

 return;

 // Go back and replace first tombstone.

 table[ firstTombstone] = key.reference ;

 table[ firstTombstone + 1] = value;

 tombstones--;

 size++;

 return;

 // Remember first tombstone.

 if (firstTombstone == -1 k == TOMBSTONE) {

 firstTombstone = index ;


 依据上面的代码可以得出一个存储规则:ThreadLocal的值在table数组中的存储位置总是为reference字段所表示的对象的下一个位置。 table[index] =key.reference; table[index+ 1] =value; 最终ThreadLocal的值会被存储在table数组中:table[index+ 1] =value;至此,set方法解析完毕。下面看一下get方法。
public T get() {

 // Optimized for the fast path.

 Thread currentThread = Thread.currentThread();

 Values values = values( currentThread);

 if (values != null) {

 Object[] table = values. table;

 int index = hash values .mask ;

 if (this .reference == table [index ]) {

 return (T) table [index + 1];

 } else {

 values = initializeValues(currentThread );

 return (T) values .getAfterMiss(this);

看完set方法后再看get就比较简单了,首先得到一个Values对象,然后求出table数组ThreadLocal.reference的下标。前文说过:ThradLocal对象(key)和相对应的value放在table数组连续的位置中。 也就是table被设计为下标为0,2,4...2n的位置存放key,而1,3,5...(2n +1 )的位置存放value。现在得到index后再index+1就是value在table数组中的下标。即value=table[index+1];return value即可。 到此想必读者对ThreadLocal为什么能在不同线程中能够为不同线程创建不同的线程副本(其实不太准确,应该是相同对象的不同值),原因就在于采用了key value形式的table数组。key为不同线程的reference,value就五花八门了。         ThreadLocal浅析到此结束。谢谢欣赏~






ThreadLocal源码分析 ThreadLocal,即线程局部变量。主要用于线程间数据隔离。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。
ThreadLocal源码解析 前几篇文章更多的是在使用层面去介绍ThreadLocal,并没有深入去理解原理。 其实学任何技术都是这样一个过程,我们最先接触到的可能是一个框架的API,然后你可能就会开始使用它;再然后会看看别人是怎么使用它的,有没有值得借鉴之处,再然后就是深入原理,看看它的底层是如何实现的,对它做一个深入的了解。 下面我们进入正题,先分析一下ThreadLocal几个重要的方法。
大神们是怎么使用ThreadLocal的? 这篇文章是关于ThreadLocal的第三篇文章。本文将挑选一些主流的Java开源框架,从源码上分析,大神们是如何使用ThreadLocal的,学习他们的设计思想。