ThreadLocal是什么?

ThreadLocal是一个线程内部存储类,提供线程内部存储功能,在一个ThreadLocal对象中,每一个线程都存储各自独立的数据,互不干扰

示例如下:

public class ThreadLocalTest {

    @Test
public void test() throws InterruptedException {
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
Thread thread1 = new Thread(new MyTask(threadLocal, 10));
Thread thread2 = new Thread(new MyTask(threadLocal, 100));
thread1.start();
thread2.start();
thread1.join();
thread2.join();
} } class MyTask implements Runnable { private ThreadLocal<Integer> threadLocal;
private int value; public MyTask(ThreadLocal<Integer> threadLocal, int value) {
this.threadLocal = threadLocal;
this.value = value;
} @Override
public void run() {
threadLocal.set(++value);
System.out.println(threadLocal.get());
}
}

源码分析

get()方法

  public T get() {
// ThreadLocalMap是ThreadLocal中的一个类内部类,而每一个Thread实例都拥有一个ThreadLocalMap实例变量用来存储线程的内部数据
     Thread t = Thread.currentThread();
// 获取线程实例变量ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 如果map!=null则表示Thread中的ThreadLocalMap之前已经实例过
if (map != null) {
// ThreadLocalMap实例中有数组实例Entry[] table用于存储真正的数据,key为ThreadLocal,value为存储的值,所以一个线程可以同时维护多个ThreadLocal
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
// 初始化ThreadLocalMap实例
return setInitialValue();
}
  
  
// getMap就是获取当前线程下的ThreadLocalMap实例
  ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

// 根据ThreadLocal获取对应的value
  private Entry getEntry(ThreadLocal<?> key) {
// 内部存储为数组形式,通过就算key的hashCode进而确认索引位置
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
// 如果map为null,则初始化ThreadLocalMap
  private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}

真实数据是存储在Thread对象的ThreadLocalMap实例中,所以每个线程都维护自己的内部数据,当有多个ThreadLocal时,每个ThreadLocal根据hashCode匹配到一个索引存储

 set()方法

  public void set(T value)         
     Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}   private void set(ThreadLocal<?> key, Object value) { // We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not. Entry[] tab = table;
int len = tab.length;
// 计算索引值
int i = key.threadLocalHashCode & (len-1);
        // ThreadLocalMap使用线性探测法来解决哈希冲突,假设计算后的i为10,该位置k不为null且与key不相等,则匹配索引为11的位置,一直重复下去直到可以插入为止
        // 当然这里不会出现走了一个循环还没有空位置可以插入
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
          // 将新设置的值替换旧值
if (k == key) {
e.value = value;
return;
}
          // 该位置没被占用,则存入新的值
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
       // 查到为空的位置插入数据 
tab[i] = new Entry(key, value);
int sz = ++size;
       
       // 判断是否需要扩容
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}

 应用实例:

当使用spring框架支持数据库事务时,需要将获取的数据库连接与当前线程绑定在一起,这时应用的就是ThreadLocal保存线程内部数据的特性,多次操作数据库使用的都是同个连接,这样才能保证事务的完成。

最新文章

  1. SQL一致性错误修复SQL
  2. [UCSD白板题] Covering Segments by Points
  3. webstorm添加vue插件支持
  4. (旧)子数涵数&#183;PS——换脸
  5. OpenGL完全教程 第一章 初始化OpenGL
  6. THE SENSE OF BEAUTY
  7. SQL Server中的分页
  8. elk 发送zabbix告警
  9. Log4Qt 使用(二)
  10. Kafka笔记--分布式环境搭建
  11. Git打补丁常见问题
  12. 深入了解C++中间mutablekeyword
  13. android Service Activity三种交互方式(付源码)(转)
  14. Java中设计模式之生产者消费者模式-4
  15. 【技巧】easyUI的datagrid,如何在翻页以后仍能记录被选中的行
  16. [20171220]toad plsql显示整形的bug.txt
  17. Javascript中的undefined、null、&quot;&quot;、0值和false的区别总结
  18. Win7 共享打印机 “错误:共享无法保存设置”
  19. C#客户端嵌入Chrome浏览器的实现
  20. apply、map、applymap、Dropna

热门文章

  1. JUC---02
  2. springboot 新建的时候 pom 第一行出现红叉,项目可以正常运行
  3. 团队作业4:第四篇Scrum冲刺博客(歪瑞古德小队)
  4. 结对项目 实现自动生成四则运算题目的程序 (C++)
  5. muduo源码解析6-condtion类
  6. 基于ABP 底层代码生成器
  7. session 机制和 httpsession 详解 (转载)
  8. seo增加外链的方法
  9. Ubuntu 20.04.1 安装软件和系统配置脚本
  10. laravel在视图中使用类似于“__PUBLIC__”,“__UPLOADS__”的操作