ThreadLocal(一):Thread 、ThreadLocal、ThreadLocalMap
一、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(一):Thread 、ThreadLocal、ThreadLocalMap的更多相关文章
- 从源码看Thread&ThreadLocal&ThreadLocalMap的关系与原理
		
1.三者的之间的关系 ThreadLocalMap是Thread类的成员变量threadLocals,一个线程拥有一个ThreadLocalMap,一个ThreadLocalMap可以有多个Threa ...
 - 深入ThreadLocal之三(ThreadLocal可能引起的内存泄露)
		
threadlocal里面使用了一个存在弱引用的map,当释放掉threadlocal的强引用以后,map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露. 最好 ...
 - ThreadLocal与Thread与Runable之间的关系
		
ThreadLocal继承Object,相当于没继承任何特殊的. ThreadLocal没有实现任何接口. ThreadLocal并不是一个Thread,而是Thread的局部变量
 - ANDROID_MARS学习笔记_S02重置版_001_Hander\Looper\Message\Thread\ThreadLocal
		
一. * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper ...
 - ThreadLocal的坑--ThreadLocal跨线程传递问题
		
1.父子线程间的传递问题 ThreadLocal的子类InheritableThreadLocal其实已经帮我们处理好了,通过这个组件可以实现父子线程之间的数据传递,在子线程中能够父线程中的Threa ...
 - 【ThreadLocal】使用ThreadLocal实现线程安全
		
非线程安全 public class UnSafeThreadLocalDemo { private int count = 0; public static void main(String[] a ...
 - ThreadLocal是什么?谈谈你对他的理解
		
1.ThreadLocal是什么 从名字我们就可以看到ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的.ThreadLocal为变 ...
 - 这4种ThreadLocal你都知道吗?
		
什么是ThreadLocal ThreadLocal类顾名思义可以理解为线程本地变量.也就是说如果定义了一个ThreadLocal, 每个线程往这个ThreadLocal中读写是线程隔离,互相之间不会 ...
 - java基础之ThreadLocal
		
早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序.Thr ...
 - 面试官:知道ThreadLocal嘛?谈谈你对它的理解?(基于jdk1.8)
		
https://zhuanlan.zhihu.com/p/99150038  西北工业大学 计算机技术硕士在读 在java的多线程模块中,ThreadLocal是经常被提问到的一个知识点,提问的 ...
 
随机推荐
- Go语言_iota用法
			
一.介绍 iota,特殊常量,可以认为是一个可以被编译器修改的常量. 在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1. io ...
 - Excel公式中使用动态计算的地址
			
例:统计A列第四行开始,到公式所在行的前一行的非空白行的个数: =COUNTA(A4:INDIRECT(ADDRESS(ROW()-,COLUMN())))
 - Orchard CMS -Migration文件更新后数据库不更新的问题 new properties not updating after migrationData migration is not working?
			
Orchard CMS - new properties not updating after migrationData migration is not working? If your mapp ...
 - [hive] hiveql  基础操作
			
1. 显示当前的数据库信息 直接修改hive.site.xml ,永久显示 2. 建表,模糊显示表信息 drop table 表名称: --删除表 show tables ;--显示所有表 sh ...
 - [React] 07 - Flux: uni-flow for react
			
相关资源 Ref: [Android Module] 03 - Software Design and Architecture Ref: Flux 架构入门教程 Ref: 详解React Flux架 ...
 - 10享元模式Flyweight
			
一.什么是享元模式 Flyweight模式也叫享元模式,是构造型模式之 一,它通过与其他类似对象共享数据来减小内存 占用. 二.享元模式的结构 三.享元模式的角色和职责 抽象享元角色: 所有具体享元类 ...
 - Android进阶:ListView性能优化异步加载图片 使滑动效果流畅
			
ListView 是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很 ...
 - VS 开发必用插件
			
C# outline --代码折叠 Indent Guides 虚线对齐 productivity power tools 功能集中在编辑.浏览以及其他常见的构造代码时会使用到的任务 Web Esse ...
 - Spring.NET依赖注入框架学习--简单对象注入
			
Spring.NET依赖注入框架学习--简单对象注入 在前面的俩篇中讲解了依赖注入的概念以及Spring.NET框架的核心模块介绍,今天就要看看怎么来使用Spring.NET实现一个简单的对象注入 常 ...
 - TensorFlow  MNIST 问题解决
			
TensorFlow MNIST 问题解决 一.数据集下载错误 错误:IOError: [Errno socket error] [Errno 101] Network is unreachable ...