深入了解ThreadLocal
2017-06-01 23:26
357 查看
最近阅读了importNew的一篇关于ThreadLocal的文章:
http://www.importnew.com/17849.html
因为之前自己也没怎么用过,所以一直也没搞懂,后来查了好多资料以后,我终于能理解里面的实现原理了。
在这里我给这篇文章的一些内容做个注解吧,重复的地方我也不说了。
ThreadLocal的用法
ThreadLocal的作用是声明出一些变量,T就相当于你所声明的变量。
longLocal可以算是一个特殊的long对象,它既不是链接文中的第一种情况:多个线程共享同一个变量。也不是第二种情况那样,每次调用都要新建一个新的变量。而是一种近似折中的方案:为每一个会调用这个变量的线程,在第一次调用或者修改longLocal的时候创建一个类型为ThreadLocal的变量。
原文中的”副本”这个词我觉得还是有差的,因为我觉得这个的本质还是在每个调用的线程里面创建一个全新的longLocal变量,通过set和get方法实现对每个线程里面的longLocal变量的访问和修改。以达到和在每个线程里面创建一个独立的long一样的效果。这样在一些特定的环境中,比如数据库的访问链接上,我们既希望链接函数是静态的,这样方便为每个线程所调用,又不希望每个线程共享同一个链接。在这种情况下,ThreadLocal就可以很好地优化效率和代码风格了。
具体这是怎么实现的呢?我们看看java内部的代码:
可能看到这里,还是有点蒙,那就再看看ThreadLocal类的内部类ThreadLocalMap 的set方法。
再看看ThreadLocal里面的set方法:
我们先来看看一般情况,当我们在一个线程里面调用longLocal里面的set方法,并传入一个long参数时,程序先通过Thread.currentThread()方法获取当前运行的线程,比如:你在main方法中运行的,那获得的是main线程,在你定义的Thread中运行的,那就获得你所定义的Thread。然后在跑longLocal.set(long)方法的这个线程里面给ThreadLocalMap写入一个你传进去的long变量。其中map的key是longLocal,而value就是你要写入的long。
同理,对于get方法:
当你在这个线程里面想找到你set进去的变量的时候,它就会以longLocal作为key去取出你映射进去的value。这就是整个ThreadLocal的作用机理,其中还有很多相关的细节,可以参考链接中的文章以及java里面的源代码。
http://www.importnew.com/17849.html
因为之前自己也没怎么用过,所以一直也没搞懂,后来查了好多资料以后,我终于能理解里面的实现原理了。
在这里我给这篇文章的一些内容做个注解吧,重复的地方我也不说了。
ThreadLocal的用法
ThreadLocal的作用是声明出一些变量,T就相当于你所声明的变量。
//声明一个泛型为Long类型的ThreadLocal ThreadLocal<Long> longLocal=new ThreadLocal();
longLocal可以算是一个特殊的long对象,它既不是链接文中的第一种情况:多个线程共享同一个变量。也不是第二种情况那样,每次调用都要新建一个新的变量。而是一种近似折中的方案:为每一个会调用这个变量的线程,在第一次调用或者修改longLocal的时候创建一个类型为ThreadLocal的变量。
原文中的”副本”这个词我觉得还是有差的,因为我觉得这个的本质还是在每个调用的线程里面创建一个全新的longLocal变量,通过set和get方法实现对每个线程里面的longLocal变量的访问和修改。以达到和在每个线程里面创建一个独立的long一样的效果。这样在一些特定的环境中,比如数据库的访问链接上,我们既希望链接函数是静态的,这样方便为每个线程所调用,又不希望每个线程共享同一个链接。在这种情况下,ThreadLocal就可以很好地优化效率和代码风格了。
具体这是怎么实现的呢?我们看看java内部的代码:
//在Thread类里面有这样一行,threadLocals是一个类似于HashMap的对象,目的在于如果程序里面有多个ThreadLocal变量,对于这个线程而言,用一个哈希表来储存这个线程里面所创建的threadLocal变量,并通过ThreadLocalMap来进行检索。 ThreadLocal.ThreadLocalMap threadLocals = null;
可能看到这里,还是有点蒙,那就再看看ThreadLocal类的内部类ThreadLocalMap 的set方法。
private void set(ThreadLocal<?> key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); 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; a8f7 } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
再看看ThreadLocal里面的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); }
我们先来看看一般情况,当我们在一个线程里面调用longLocal里面的set方法,并传入一个long参数时,程序先通过Thread.currentThread()方法获取当前运行的线程,比如:你在main方法中运行的,那获得的是main线程,在你定义的Thread中运行的,那就获得你所定义的Thread。然后在跑longLocal.set(long)方法的这个线程里面给ThreadLocalMap写入一个你传进去的long变量。其中map的key是longLocal,而value就是你要写入的long。
同理,对于get方法:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { T result = (T)e.value; return result; } } return setInitialValue() }
当你在这个线程里面想找到你set进去的变量的时候,它就会以longLocal作为key去取出你映射进去的value。这就是整个ThreadLocal的作用机理,其中还有很多相关的细节,可以参考链接中的文章以及java里面的源代码。
相关文章推荐
- 深入了解ThreadLocal
- ThreadLocal 深入了解
- Android自定义View的实现方法,带你一步步深入了解View(四)
- 深入了解以“.”结尾的文件夹
- ThreadLocal深入
- 平衡球游戏开发教程(四)--深入了解WP7游戏底层原理
- 深入了解C语言
- 深入了解 Dojo 的核心接口
- 深入了解MyBatis参数
- 深入分析ThreadLocal
- 深入了解MyBatis参数
- js的深入了解
- 深入理解ThreadLocal
- iOS开发之深入了解推送全解析,你不可不知的所有 Tips!
- Android视图状态及重绘流程分析,带你一步步深入了解View(三)
- 深入理解ThreadLocal看了一遍尤自觉得不够
- RabbitMQ系列(二)深入了解RabbitMQ工作原理及简单使用
- 深入了解epoll 函数
- git深入了解
- 深入了解struts中的struts-config.xml