ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。

  这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

  我们从源码的角度来分析这个问题。

  首先定义一个ThreadLocal:

public class ConnectionUtil {
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
private static Connection initConn = null;
static {
try {
initConn = DriverManager.getConnection("url, name and password");
} catch (SQLException e) {
e.printStackTrace();
}
} public Connection getConn() {
Connection c = tl.get();
if(null == c) tl.set(initConn);
return tl.get();
} }

  这样子,都是用同一个连接,但是每个连接都是新的,是同一个连接的副本。

  那么实现机制是如何的呢?

  1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。

/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

  2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

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();
}

  3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。

  4、总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。

  5、应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。

  6、其实说再多也不如看一下源码来得清晰。如果要看源码,其中涉及到一个WeakReference和一个Map,这两个地方需要了解下,这两个东西分别是a.Java的弱引用,也就是GC的时候会销毁该引用所包裹(引用)的对象,这个threadLocal作为key可能被销毁,但是只要我们定义成他的类不卸载,tl这个强引用就始终引用着这个ThreadLocal的,永远不会被gc掉。b.和HashMap差不多。

  事实上,从本质来讲,就是每个线程都维护了一个map,而这个map的key就是threadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那肯定就不存在线程安全问题,总体来讲,ThreadLocal这个变量的状态根本没有发生变化,他仅仅是充当一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮我们做了这个事情。

ThreadLocal应用范例:

http://www.cnblogs.com/wangzhongqiu/p/7542110.html

最新文章

  1. 使用Project进行项目管理 - 项目管理系列文章
  2. 用js 向h5 中的table 动态添加数据 (简单实现)
  3. Nginx-uri、request_uri、document_uri之间的区别
  4. xUtils类库的使用
  5. SharePoint 2010 最佳实践学习总结------第1章 SharePoint Foundation开发基础
  6. jQuery语法总结及注意事项
  7. 高可用集群(HA)之Keeplived原理+配置过程
  8. lsof-列出当前系统打开文件
  9. Delphi中Android运行和JNI交互分析
  10. 关于oracle数据库(3)
  11. Android闪光灯操作
  12. 【new File(String Path)加载资源问题】
  13. Java自己动手写连接池二
  14. Git详解之八:Git与其他系统
  15. Elasticsearch(ES)API 增删查改常用操作
  16. JavaScript面向对象--记录防忘记(一)
  17. ui自动化:python+appium----环境搭建
  18. android 给LinearLayout中添加一定数量的控件,并让着一定数量的控件从右到左移动,每隔若干秒停顿一下,最后一个view链接第一个view,然后继续移动循环往复,形成一个死循环简单动画效果
  19. Javascript 检测键盘按键
  20. docker同步时区时间

热门文章

  1. .net MVC使用NPOI读取Excel模板,再写入数据
  2. xgboost应用
  3. 数据结构(六)查找---多路查找树(B树)
  4. Python基础(正则、序列化、常用模块和面向对象)-day06
  5. Idea下安装Lombok插件
  6. Spring中的Bean配置
  7. mvc小技巧
  8. D - Laying Cables Gym - 100971D (单调栈)
  9. k8s系列~docker mysql
  10. shiro授权及自定义realm授权(七)