ThreadLocal知识总结
一、ThreadLocalMap是ThreadLocal的内部类、Thread持有ThreadLocalMap的引用
Entry类继承了WeakReference<ThreadLocal<?>>,即每个Entry对象都有一个ThreadLocal的弱引用(作为key),这是为了防止内存泄露。
key变为一个不可达的对象(null),这个Entry就可以被GC了。
static class ThreadLocalMap { /**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value; Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
1.ThreadLocalMap成员变量分析,放入第一个元素时,才生成Entry数组实例
/*** The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16; /**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table; /**
* The number of entries in the table.
*/
private int size = 0; /**
* The next size value at which to resize.
*/
private int threshold; // Default to 0 /**
* Set the resize threshold to maintain at worst a 2/3 load factor.
*/
private void setThreshold(int len) {
threshold = len * 2 / 3;
} /**
* Increment i modulo len.
*/
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
} /**
* Decrement i modulo len.
*/
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
} /**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
ThreadLocalMap构造函数的第一个参数就是该ThreadLocal实例(this),第二个参数就是要保存的线程本地变量。
构造函数首先创建一个长度为16的Entry数组,然后计算出firstKey对应的哈希值,然后存储到table中,并设置size和threshold。
注意一个细节,计算hash的时候里面采用了hashCode & (size - 1)的算法,这相当于取模运算hashCode % size的一个更高效的实现(和
HashMap中的思路相同)。正是因为这种算法,我们要求size必须是2的指数,因为这可以使得hash发生冲突的次数减小。
2、Thread持有两个ThreadLocalMap的引用,一个用于保存当前线程的局部变量,另一个保存父线程的局部变量
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null; /*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
二、ThreadLocal的set()方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value); //以ThreadLocal为键
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); //以ThreadLocal为键
}
ThreadLocal的get()方法
public T get() {
Thread t = Thread.currentThread(); //得到当前线程
ThreadLocalMap map = getMap(t); //得到当前线程相关的ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
} ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocal在Hibernate中的应用
private static final ThreadLocal threadSession = new ThreadLocal(); public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
三、总结
我们在多线程的开发中,经常会考虑到的策略是对一些需要公开访问的属性通过设置同步的方式来访问。这样每次能保证只有一个线程访问它,不会有冲突。
但是这样做的结果会使得性能和对高并发的支持不够。在某些情况下,如果我们不一定非要对一个变量共享不可,而是给每个线程一个这样的资源副本,让他们可
以独立都各自跑各自的,这样不是可以大幅度的提高并行度和性能了吗?
还有的情况是有的数据本身不是线程安全的,或者说它只能被一个线程使用,不能被其他线程同时使用。如果等一个线程使用完了再给另外一个线程使用就
根本不现实。这样的情况下,我们也可以考虑用ThreadLocal。一个典型的情况就是我们连接数据库的时候通常会用到连接池。而对数据库的连接不能有多个线程
共享访问。这个时候就需要使用ThreadLocal了。
private static ThreadLocal<Connection> connectionHolder =
new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
}; pubic static Connection getConnection() {
return connectionHolder.get();
}
四、ThreadLocal使用总结
ThreadLocal对象建议使用static修饰。这个变量是针对一个线程内所有操作共有的,
所以设置为静态变量,所有此类实例共享此静态变量 ,也就是说在类第一次被使用时装载,只分配一块存储空间
ThreadLocal
instances are typically private static fields in classes that wish to associate state with a thread
(e.g., a user ID or Transaction ID).
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal
instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection
(unless other references to these copies exist).
参考:
深入理解 Java 之 ThreadLocal 工作原理
ThreadLocal知识总结的更多相关文章
- ThreadLocal浅析
1.ThreadLocal的大体理解 ThreadLocal 又名 线程局部变量,是 Java 中一种较为特殊的 线程绑定机制,可以为每一个使用该变量的线程都提供一个变量值的副本,并且每一个线程都可以 ...
- java面试填坑解惑篇
感谢原文出处:https://www.cnblogs.com/javazhiyin/ NO1.请简单描述JDK和JRE的区别? NO1.回答JDK和JRE的区别这道题,首先要回答两个名次的概念,JDK ...
- Java面试题必备知识之ThreadLocal
老套路,先列举下关于ThreadLocal常见的疑问,希望可以通过这篇学习笔记来解决这几个问题: ThreadLocal是用来解决什么问题的? 如何使用ThreadLocal? ThreadLocal ...
- 线程知识-ThreadLocal使用详解
最近在看Spring的时候回顾了一下ThreadLocal,下面是ThreadLocal的使用说明. 概述 首先,谈到ThreadLocal的使用,我们先来了解一下ThreadLocal是什么?Thr ...
- 【Java】ThreadLocal细节分析
ThreadLocal通过中文解释就是线程本地变量,是线程的一个局部变量.根据哲学家黑格尔“的存在即合理”的说法,ThreadLocal的出现肯定是有它的意义,它的出现也是因为多线程的一个产物.Thr ...
- [Java面试三]JavaWeb基础知识总结.
1.web服务器与HTTP协议 Web服务器 l WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. l Internet上供外界访问的Web资源分为: • 静 ...
- android 界面设计基本知识Ⅱ
上一章讲述了Android界面设计时,一些基本控件的使用,本章主要讲述自定义控件,Fragment和Headler线程机制. 1.自定义控件 (1)基本知识 dp.sp和dx px:像素点 ...
- 线程本地变量ThreadLocal源码解读
一.ThreadLocal基础知识 原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板 ...
- Android消息机制之ThreadLocal的工作原理
来源: http://blog.csdn.net/singwhatiwanna/article/details/48350919 很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI ...
随机推荐
- POJ2125 Destroying The Graph(二分图最小点权覆盖集)
最小点权覆盖就是,对于有点权的有向图,选出权值和最少的点的集合覆盖所有的边. 解二分图最小点权覆盖集可以用最小割: vs-X-Y-vt这样连边,vs和X部点的连边容量为X部点的权值,Y部和vt连边容量 ...
- BZOJ2707 : [SDOI2012]走迷宫
首先求出SCC缩点,E[T]=0,按拓扑序计算 对于无边连出的块,如果不是T所在块,则称该块是死路块 对于一个块,如果其中的点连出的边是死路块,则它也是死路块 否则对于每块进行高斯消元求出期望 如果S ...
- HDU 2896 (AC自动机模板题)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2896 题目大意:多个模式串.多个匹配串.其中串的字符范围是(0~127).问匹配串中含有哪几个模式串 ...
- MONO 说谈
Xamarin android现在到底依赖Dalvik不?是部分依赖的 驱动 编译后的IL经过CLR并不能直接成为机器码,而是要借助Dalvik才能成为机器码吗? 而是关于Android的驱动部分主 ...
- TYVJ P1013 找啊找啊找GF Label:动态规划
做题记录:2016-08-15 22:19:04 背景 MM七夕模拟赛 描述 "找啊找啊找GF,找到一个好GF,吃顿饭啊拉拉手,你是我的好GF.再见.""诶,别再见啊.. ...
- BZOJ3772: 精神污染
Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区, ...
- JQuery图形插件,Highcharts平滑线条处理方法
第一种:静态数据 $('#THChartDiv').highcharts({ chart: { type: 'spline' }, title: { text:过程线' }, xAxis: { tit ...
- iOS开发之--NSPredicate
简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 定义(最常用到的方法): NSPredicate *ca = [NSPred ...
- shenyi 语录
[讲师]沈逸(65480539) 2016-06-08 14:58:42 会centos 转redhat是分分钟的事 [讲师]沈逸(65480539) 2016-06-08 14:58:54 查看 ...
- 新建childTest文件夹,里面依然放进我们需要的.py文件即可
一.模块 我们编写文件:a.py,放在C:\Python34\Lib\sit-packages下,里面写上一句代码为: print('this is a') 之后我们就可以在我们的代码里面引用a.py ...