本文转自http://blog.csdn.net/huachao1001/article/details/51970237

ThreadLocal的使用相信大家都比较熟悉,但是ThreadLocal内部是如何做到为不同线程保存不同的副本的呢?能看到这篇文章,说明你也跟我一样好奇。接下来我们一层一层解开ThreadLocal的面纱吧~

1. 涉及到的几个重要类

ThreadLocal里面的实现,主要涉及到以下几个重要类:

  • Thread:大家很熟悉的线程类,一个Thread类自然代表一个线程。
  • ThreadLocal:既然本文是要解析ThreadLocal类,自然就离不开这个类啦~。
  • ThreadLocalMap:可以看成一个HashMap,但是它本身具体的实现并没有实现继承HashMap甚至跟java.util.Map都沾不上一点关系。只是内部的实现跟HashMap类似(通过哈希表的方式存储)。
  • ThreadLocalMap.Entry:把它看成是保存键值对的对象,其本质上是一个WeakReference<ThreadLocal>对象。

主要涉及到的类暂时只有这些,其中ThreadLocalMapThreadLocalMap.Entry的源码解析留到下一篇文章讲,在本文中,我们暂时不去牵扯它们的实现细节,我们只需在心中默默地为ThreadLocalMap打上HashMap的标签,把它暂时先当成HashMap来看待,ThreadLocalMap.Entry看成是保存<键,值>的对象。

2. ThreadLocal数据存取

2.1 set函数

我们知道,在使用ThreadLocal时,首先创建ThreadLocal对象,然后再调用其set(T)T get()方法。我们从这些点切入,首先是构造函数如下:

public ThreadLocal() {
}
  • 1
  • 2

可以看到,构造函数没有任何实现。接下来我们再从set函数切入:

/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

代码整体流程很简单:

先拿到保存键值对的ThreadLocalMap对象实例map,如果map为空(第一次调用的时候map值为null),则去创建一个ThreadLocalMap对象并赋值给map,并把键值对保存到map中。

当然了,虽然整体流程看起来简单,其内部实现需要我们理清!

我们看到,首先是拿到当前线程实例t,任何将t作为参数获取ThreadLocalMap对象。为什么需要通过Thread类来获取ThreadLocalMap对象呢?Thread类和ThreadLocalMap有什么联系?这些需要我们去看看getMap(Thread t)函数的实现:

ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
  • 1
  • 2
  • 3

我们看到,getMap的实现非常简单!!!仅仅返回Thread实例的threadLocals属性。Thread中的ThreadLocalMap属性声明如下:

ThreadLocal.ThreadLocalMap threadLocals = null;
  • 1

我们先理一理,ThreadLocalset(T)函数中,首先是拿到当前线程Thread对象中的ThreadLocalMap对象实例threadLocals ,然后再将需要保存的值保存到threadLocals里面。

换句话说,每个线程引用的ThreadLocal副本值都是保存在当前线程Thread对象里面的。存储结构为ThreadLocalMap类型,ThreadLocalMap保存的键类型为ThreadLocal,值为副本值

2.2 get函数

有了set函数中的解析,我们对get函数就更容易理解了!先看看get函数源码:

/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

同样的道理,拿到当前线程Thread对象实例中保存的ThreadLocalMap对象map,然后从map中读取键为this(即ThreadLocal类实例)对应的值。

如果map不是null,直接从map里面读取就好,如果map==null,那么我们需要对当前线程Thread对象实例中保存的ThreadLocalMap对象new一下。即通过setInitialValue函数来创建,setInitialValue函数具体实现如下:

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

代码很简单,通过createMap来创建ThreadLocalMap对象,前面set函数里面创建ThreadLocalMap也是通过createMap来的,我们看看createMap具体实现:

void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
  • 1
  • 2
  • 3

这下对ThreadLocal的存取机制彻底清楚了吧!接下来一节我们以图形的形式做个总结。

threadlocal彻底理解,深刻的更多相关文章

  1. ThreadLocal深入理解二

    转载:http://doc00.com/doc/101101jf6 今天在看之前转载的博客:ThreadLocal的内部实现原理.突然有个疑问, 按照threadLocal的原理, 当把一个对象存入到 ...

  2. ThreadLocal深入理解一

    转载:http://www.cnblogs.com/dolphin0520/p/3920407.html 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使 ...

  3. Java中的ThreadLocal深入理解

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  4. ThreadLocal的理解与应用场景分析

    对于Java ThreadLocal的理解与应用场景分析 一.对ThreadLocal理解 ThreadLocal提供一个方便的方式,可以根据不同的线程存放一些不同的特征属性,可以方便的在线程中进行存 ...

  5. Python中ThreadLocal的理解与使用

    一.对 ThreadLocal 的理解 ThreadLocal,有的人叫它线程本地变量,也有的人叫它线程本地存储,其实意思一样. ThreadLocal 在每一个变量中都会创建一个副本,每个线程都可以 ...

  6. java中threadlocal的理解

    [TOC] #java中threadlocal的理解##一.threadlocal的生命周期和ThreadLocalMap的生命周期可以吧TreadLocal看做是一个map来使用,只不过这个map是 ...

  7. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

  8. 我对ThreadLocal的理解

    声明:小弟菜狗一个.对ThreadLocal的描写叙述和理解难免有所偏差 近期由于须要深入的了解android的handler消息机制而去查看了Looper的源代码.众所周知在主线程中是不须要在程序猿 ...

  9. ThreadLocal深入理解与内存泄露分析

    ThreadLocal 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本.所以每个线程都能够独立地改变自己的副本.而不会影响其他线程所相应的副本. ...

随机推荐

  1. 网站服务器压力Web性能测试(4):服务器压力Web性能测试小结

    1.Apache Bench,Webbench,http_load对网站压力Web性能进行测试时,为了得到更加客观和准确的数值,应该从远程访问.局域网访问和本地等多个方面进行全方位的测试.一般用127 ...

  2. maven项目的多级目录

    刚刚把一个开源的项目变成maven项目来进行管理,由于是多级的目录(以前配置的都是单级的目录),所以记录一下pom文件是怎么配置的. 一.目录结构 如下,maven的结构图,红字是表示完整的项目

  3. 2017百度春招<度度熊买帽子的问题>

    题目: 度度熊想去商场买一顶帽子,商场里有N顶帽子,有些帽子的价格可能相同.度度熊想买一顶价格第三便宜的帽子,问第三便宜的帽子价格是多少? 数组中找到第三小的数字  注意边界条件 用STL中的set来 ...

  4. C#面向对象(OOP)入门—第二天—多态和继承(继承)

    介绍: 第一天的内容主要是不同情形下的方法重载.这一部分则主要讲面向对象中继承的概念.首先用一个要点图形来定义继承. 继承 一个简单的例子: ClassA: class ClassA:ClassB { ...

  5. Leetcode 之Binary Tree Postorder Traversal(44)

    后序遍历,比先序和中序都要复杂.访问一个结点前,需要先判断其右孩子是否被访问过.如果是,则可以访问该结点:否则,需要先处理右子树. vector<int> postorderTravers ...

  6. NOIP 2012 Day1

    tags: NOIP 模拟 倍增 高精 Python categories: 信息学竞赛 总结 Luogu P1079 Vigenère 密码 Solution 表示并不是很懂其他人发的题解. 我是这 ...

  7. django celery异步框架

    描述:实现运维平台的异步执行与定时任务,以下简单描述了安装过程及使用.   安装django和celery pip install django pip install celery pip inst ...

  8. LeetCode解题报告—— Number of Islands & Bitwise AND of Numbers Range

    1. Number of Islands Given a 2d grid map of '1's (land) and '0's (water), count the number of island ...

  9. 《深入浅出MyBatis技术原理与实战》——6. MyBatis的解析和运行原理

    MyBatis的运行分为两大部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程. 6.1 涉及的技术 ...

  10. 深度学习方法:受限玻尔兹曼机RBM(四)对比散度contrastive divergence,CD

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入 上篇讲到,如果用Gibbs Sa ...