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保存线程内部数据的特性,多次操作数据库使用的都是同个连接,这样才能保证事务的完成。

ThreadLocal源码分析与实践的更多相关文章

  1. 并发编程(四)—— ThreadLocal源码分析及内存泄露预防

    今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...

  2. ThreadLocal源码分析-黄金分割数的使用

    前提 最近接触到的一个项目要兼容新老系统,最终采用了ThreadLocal(实际上用的是InheritableThreadLocal)用于在子线程获取父线程中共享的变量.问题是解决了,但是后来发现对T ...

  3. Java多线程学习之ThreadLocal源码分析

    0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...

  4. Java并发编程之ThreadLocal源码分析

    ## 1 一句话概括ThreadLocal<font face="微软雅黑" size=4>  什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象 ...

  5. 【JAVA】ThreadLocal源码分析

    ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...

  6. 并发-ThreadLocal源码分析

    ThreadLocal源码分析 参考: http://www.cnblogs.com/dolphin0520/p/3920407.html https://www.cnblogs.com/coshah ...

  7. 自定义View系列教程04--Draw源码分析及其实践

    深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...

  8. Java -- 基于JDK1.8的ThreadLocal源码分析

    1,最近在做一个需求的时候需要对外部暴露一个值得应用  ,一般来说直接写个单例,将这个成员变量的值暴露出去就ok了,但是当时突然灵机一动(现在回想是个多余的想法),想到handle源码里面有使用过Th ...

  9. ThreadLocal详解,ThreadLocal源码分析,ThreadLocal图解

    本文脉路: 概念阐释 ---->  原理图解  ------> 源码分析 ------>  思路整理  ----> 其他补充. 一.概念阐述. ThreadLocal 是一个为 ...

随机推荐

  1. Jmeter 常用函数(25)- 详解 __V

    如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.html 作用 执行变量名表达式,并返回执行结果 它可 ...

  2. docker 启动容器失败 id already in use

    问题:id already in use 解决:/etc/docker/daemon.json {"shutdown-timeout": 60}

  3. Fisher Coffee 测评(非严格控温控水)

    Fisher Coffee 测评(非严格控温控水) 咖啡生产批次:2020-05-29 打分区间:1~5,0.5间隔 批次:2020.6.3 酸为主,苦为主. 无甘,有甘,微甘,较甜,甘甜. 不苦,有 ...

  4. 算法-图(4)用边表示活动的网络(AOE网络)Activity On Edge Network

    有向边表示活动,权值表示活动的持续时间,顶点表示事件. 只有一个开始点和完成点,称为源点.汇点,完成工程时间取决于从源点到汇点的最长路径长度,即在这条路径(关键路径)上所有活动的持续时间之和.关键路径 ...

  5. (新手向)N皇后问题详解(DFS算法)

    非常经典的一道题: N皇后问题: 国际象棋中皇后的势力范围覆盖其所在的行.列以及两条对角线,现在考察如下问题:如何在n x n的棋盘上放置n个皇后,使得她们彼此互不攻击 . 免去麻烦我们这里假定n不是 ...

  6. LG P6788 「EZEC-3」四月樱花

    Description 在樱花盛开的四月,Muxii 望着满天飘落的樱花,向身旁的 ZZH 问道: “究竟有多少朵樱花在这个四月飘落?” ZZH 答道:“樱花飘落的朵数  $s$与时间 $t$ 有如下 ...

  7. windows设置定时执行脚本

    如果你写了一些Python程序,想要在特定的时间进行执行,例如你想让一段爬虫程序在每天的上午10点执行一次,那么我们就可以来使用windows自带的定时任务进行设置.由于Windows系统,无法使用L ...

  8. linux系统工程师修改打开文件数限制代码教程。服务器运维技术

    提示linux文件打开错误,修改linux打开文件数参数. /etc/pam.d/login 添加 session required /lib/security/pam_limits.so 注意看这个 ...

  9. 虚拟机安装:VirtualBox上安装Ubuntu

    在Win10 中使用VirtualBox安装Ubuntu 本教程将指引读者在Windows10操作系统下使用开源虚拟机软件VirtualBox安装Ubuntu,读者也可以使用其他虚拟机VMware W ...

  10. 【学习中】Fitness Schedule

    章节 内容 签到 第1周:步伐 √第1课(34分钟) 跑步1分钟 行走2分钟 共做8次 4月24日 √第2课(28分钟) 跑步1分钟 行走2分钟 共做6次 4月27日 √第3课(31分钟) 跑步1分钟 ...