threadlocal彻底理解,深刻
本文转自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>
对象。
主要涉及到的类暂时只有这些,其中ThreadLocalMap
和ThreadLocalMap.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
我们先理一理,ThreadLocal
的set(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彻底理解,深刻的更多相关文章
- ThreadLocal深入理解二
转载:http://doc00.com/doc/101101jf6 今天在看之前转载的博客:ThreadLocal的内部实现原理.突然有个疑问, 按照threadLocal的原理, 当把一个对象存入到 ...
- ThreadLocal深入理解一
转载:http://www.cnblogs.com/dolphin0520/p/3920407.html 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使 ...
- Java中的ThreadLocal深入理解
提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...
- ThreadLocal的理解与应用场景分析
对于Java ThreadLocal的理解与应用场景分析 一.对ThreadLocal理解 ThreadLocal提供一个方便的方式,可以根据不同的线程存放一些不同的特征属性,可以方便的在线程中进行存 ...
- Python中ThreadLocal的理解与使用
一.对 ThreadLocal 的理解 ThreadLocal,有的人叫它线程本地变量,也有的人叫它线程本地存储,其实意思一样. ThreadLocal 在每一个变量中都会创建一个副本,每个线程都可以 ...
- java中threadlocal的理解
[TOC] #java中threadlocal的理解##一.threadlocal的生命周期和ThreadLocalMap的生命周期可以吧TreadLocal看做是一个map来使用,只不过这个map是 ...
- ThreadLocal简单理解
在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...
- 我对ThreadLocal的理解
声明:小弟菜狗一个.对ThreadLocal的描写叙述和理解难免有所偏差 近期由于须要深入的了解android的handler消息机制而去查看了Looper的源代码.众所周知在主线程中是不须要在程序猿 ...
- ThreadLocal深入理解与内存泄露分析
ThreadLocal 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本.所以每个线程都能够独立地改变自己的副本.而不会影响其他线程所相应的副本. ...
随机推荐
- MVC自定义路由实现URL重写,SEO优化
//App_Start-RouteConfig.cs public class RouteConfig { public static void RegisterRoutes(RouteCollect ...
- 广度优先搜索--POJ迷宫问题
Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, ...
- 图论-最小生成树-Kruskal算法
有关概念: 最小生成树:在连通图G中,连接图G所有顶点且总权最小的边构成的树 思路: 首先对边按权从小到大排序,紧接着枚举每一条边,如果两个结点的祖先结点不同(并查集),则连上此边,直到边数等于结点数 ...
- canvas写的地铁地图
更新: 18-9-21:填了个坑,更新了canvas绘制过程. 根据的是百度提供的坐标,canvas的坐标是大的坐标在后面,所以跟实际生活方向相反. 所以canvas里的北方在下方,实际生活中北方在上 ...
- MiCode108 猜数字
Description 相传,十八世纪的数学家喜欢玩一种猜数字的小游戏,规则如下: 首先裁判选定一个正整数数字 N (2 \leq N \leq 200)N(2≤N≤200),然后选择两个不同的整数X ...
- WordPress函数query_posts用法汇总
最近经常有网友跟我咨询WordPress函数query_posts的相关用法,说起来query_posts实在是太强大,参数无数,用法更是无数,如果让我说它的用法,我根本没法一一说清楚.开始之前,你可 ...
- Go语言练习之方法,接口,并发
多练练,有感觉了就写实际的东东. package main import ( "fmt" "math" "os" "time&qu ...
- AC日记——色板游戏 洛谷 P1558
色板游戏 思路: sb题: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 struct Tre ...
- sublime text光标移入移出括号的快捷键设置
使用sublime text每次输入完一个函数或者标签,光标一般都是停留在括号中间,要跳出来要使用左右方向键或者end键 这俩键键区比较远,按起来麻烦,可以自己设置快捷键实现跳出的功能. 原来的快捷键 ...
- 【Java NIO】一文了解NIO
Java NIO 1 背景介绍 在上一篇文章中我们介绍了Java基本IO,也就是阻塞式IO(BIO),在JDK1.4版本后推出了新的IO系统(NIO),也可以理解为非阻塞IO(Non-Blocking ...