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. Hyperledger Fabric【区块链学习一】

    Hyperledger Fabric 学习 什么是区块链 什么是区块链在我们没有接触的时候,只知道它是一个去中心化的存储方式.当我们发生交易,或者动作的时候我们会将记录通知给所有参与者共同维护,达到去 ...

  2. idea 推送jar包到maven私库

    1.推送到本地仓库 idea直接install即可 2.推送到公司私库 2.1 使用配置公司仓库地址的setting文件 <?xml version="1.0" encodi ...

  3. 团队作业4:第三篇Scrum冲刺博客(歪瑞古德小队)

    目录 一.Daily Scrum Meeting 1.1 会议照片 1.2 项目进展 二.项目燃尽图 三.签入记录 3.1 代码/文档签入记录 3.2 Code Review 记录 3.3 issue ...

  4. 关于c++11 memory order的理解

    关于C++memory_order的理解 看了c++并发编程实战的内存模型部分后,一直对memory_order不太懂,今天在知乎发现了百度的brpc,恰好有关于原子操作的文档,感觉解释的很好.为了加 ...

  5. 风变编程-Python基础语法

    第0关-千寻的名字 目录 1.范例1 2.范例2 1.知识点总结 2.范例 1)单引号和双引号 2)三引号 3)转义字符 1.知识点总结 1)变量 2)变量名 3)变量的命名规范 4)等于与赋值的区别 ...

  6. 区块链入门到实战(30)之Solidity – 基础语法

    一个 Solidity 源文件可以包含任意数量的合约定义.import指令和pragma指令. 让我们从一个简单的 Solidity 源程序开始.下面是一个 Solidity 源文件的例子: prag ...

  7. 区块链入门到实战(27)之以太坊(Ethereum) – 智能合约开发

    智能合约的优点 与传统合同相比,智能合约有一些显著优点: 不需要中间人 费用低 代码就是规则 区块链网络中有多个备份,不用担心丢失 避免人工错误 无需信任,就可履行协议 匿名履行协议 以太坊(Ethe ...

  8. Python编程进阶,Python如何实现多进程?

    进程part1 一.进程介绍 1.获取子父进程 2.进程的基本使用 2.创建带有参数的进程 3.进程之间的数据彼此隔离 4.多个进程之间的异步并发 二.join 1.基本语法 2.使用自定义类的方法创 ...

  9. CRMEB单商户商城系统v4.0源码,含前端uni-app源码

    CRMEB商城系统是基于ThinkPhp6.0+Vue开发的一套新零售移动电商系统,CRMEB系统就是集客户关系管理+营销电商系统,能够快速积累客户.会员数据分析.智能转化客户. 有效提高销售.会员维 ...

  10. 【转】mac上安装gradle

    http://www.douban.com/note/311599602/ 首先,先download最新版本的gradle,网址如下:http://www.gradle.org/get-started ...