Java并发机制(4)--ThreadLocal线程本地变量(转)
个人理解:
说明:看了博客园中大神写的ThreadLocal的详解,感觉还是有些迷糊,下面用自己的理解简单描述下ThreadLocal的机制(难免有误);
1、首先ThreadLocal用于存储对应线程的本地变量,放在哪里呢?每一个线程维护一个threadlocals(这个threadlocals我认为是由ThreadLcoal创建的,是当前线程上的属性,多个ThreadLocal只创建一个:通过ThreadLocal中的createMap方法: t.threadLocals = new ThreadLocalMap(this, firstValue); ),它事实上就是一个ThreadLocalMap,是ThreadLocal的内部类,可以理解为一张Map表,其中包含了Entry键值对,故线程的本地变量就放在这个Entry中:Entry:<ThreadLocal,value>形式,键值对里的ThreadLocal我认为是你用的时候new出来的ThreadLocal,而不是每个线程所维护的那一个ThreadLoca。(不是很确定,但是想到一个线程要放多个变量的话,每个变量new一个ThreadLocal,这些ThreadLocal做为key放在线程所维护的那个ThreadLocalMap中?)。
2、由1中知道,一个ThreadLocal只能存放一个线程的本地变量,所以要存放第二个线程的本地变量,就应该在new ThreadLocal进行存储,所以 private static final ThreadLocal <T> t1=new Threadlocal<>() 这句话可以写在工具类中,且作为静态成员变量使用。
这里我一开始理解错误:把ThreadLocalMap理解成类似于HashMaple了,然后ThreadLocal保存了所有线程的本地变量,这样一个ThreadLocal就可以了?那么多线程访问一个ThreadLocal(共享)依然需要加锁,失去了原来的意义。
3、ThreadLocal的方法理解(源码分析):
3.1、threadlocal.get()方法:
step1:根据当前线程t获取对应的TheradLocalMap;
step2:如果ThreadLocalMap!=null;获取内部的Entry,返回val,结束;
如果ThreadLocalMap==null,调用setInitialValue()方法设置初始值;
step3:setInitialValue()方法判断是否有ThreadLocalMap,(没有则创建),
并调用initialValue()方法获得初始value,这个value=null;
所以,new 出来的Threadlocal要先set(value),然后get(),否则get到null;
或者也可以重写initialValue方法(默认返回一个初始值);
3.2、threadlocal.set()方法:赋值,不多描述。
4、弱引用问题:ThreadLocalMap使用ThreadLocal的弱引用作为key,,如果一个ThreadLocal没有外部强引用引用他,那么系统gc的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,无法访问到这些value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,永远无法回收,造成内存泄露。
JDK建议将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,并主动调用remove函数释放。
总结如下:
首先,要区分threadlocals、ThreadLocalMap、ThreadLocal这三者。
其次,ThreadLcoal的主要机制如下。
(1)每个线程Thread内部有一个threadlocals属性,它是ThreadLocal.ThreadLocalMap类型的,内部的Entry<ThreadLocal,value>用来保存变量的副本,只供线程自己使用。
(2)最开始,threadlocals是空的,通过Threadlocal的get或者set方法可以初始化threadlocals(调用createMap方法,源代码在1种),然后你每存一个变量副本,需要new ThreadLocal()出来,存几个new几个,threadlocals以该ThreadLocal为key,变量副本为value进行保存。
(2)我们可以通过ThreadLocal.get()获取对应的ThreadLocal的value。通过ThreadLcoal.set(value)来设置更改threadlocals中的值。
参考资料:
1、博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920407.html
2、http://www.iteye.com/topic/103804
3、http://www.cnblogs.com/xzwblog/p/7227509.html
以下给出两段实例代码,也来自上述参考资料:
1、hibernate中典型的ThreadLocal的应用,获取session;
...
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;
}
2、
public class Test {
ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
ThreadLocal<String> stringLocal = new ThreadLocal<String>();
public void set() {
longLocal.set(Thread.currentThread().getId());
//这里先获取每一个线程thread的ThreadLocalMap,然后map.set(this, value),this就是当前的ThreadLocal,value就是getId的值,也就为每个线程创建完副本,并存放入线程的ThreadLocalMap中,从而实现了线程本地变量的副本创建。
stringLocal.set(Thread.currentThread().getName());
} public long getLong() {
return longLocal.get();
} public String getString() {
return stringLocal.get();
} public static void main(String[] args) throws InterruptedException {
final Test test = new Test(); test.set();
System.out.println(test.getLong());
System.out.println(test.getString()); Thread thread1 = new Thread(){
public void run() {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
};
};
thread1.start();
thread1.join(); System.out.println(test.getLong());
System.out.println(test.getString());
}
}

------------------------------------------------------------------------------------------终-----------------------------------------------------------------------------------------------------------------------------------------------
详情移步:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920407.html
Java并发机制(4)--ThreadLocal线程本地变量(转)的更多相关文章
- Threadlocal线程本地变量理解
转载:https://www.cnblogs.com/chengxiao/p/6152824.html 总结: 作用:ThreadLocal 线程本地变量,可用于分布式项目的日志追踪 用法:在切面中生 ...
- ThreadLocal 线程本地变量 及 源码分析
■ ThreadLocal 定义 ThreadLocal通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量 ...
- ThreadLocal线程本地变量
首先说明ThreadLocal存放的值是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,这样处理后,能够优雅的解决一些实际问题,比如hibernate中的OpenSessi ...
- 深入理解线程本地变量ThreadLocal
ThreadLocal理解: 假设在多线程并发环境中.一个可变对象涉及到共享与竞争,那么该可变对象就一定会涉及到线程间同步操作,这是多线程并发问题. 否则该可变对象将作为线程私有对象,可通过Threa ...
- Java并发(二十):线程本地变量ThreadLocal
ThreadLocal是一个本地线程副本变量工具类. 主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的 ...
- 深入理解java:2.4. 线程本地变量 java.lang.ThreadLocal类
ThreadLocal,很多人都叫它做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多. 可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那样每个线程可以访问自己内 ...
- 线程本地变量ThreadLocal
一.本地线程变量使用场景 并发应用的一个关键地方就是共享数据.如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性.这意味 ...
- java线程本地变量
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名为Thre ...
- 线程本地变量ThreadLocal源码解读
一.ThreadLocal基础知识 原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板 ...
随机推荐
- react 也就这么回事 02 —— JSX 插值表达式、条件渲染以及列表渲染
我们已经学会了 React 创建元素和渲染元素 ReactDOM.render(<div>Hello React!</div>, document.getElementById ...
- 5、CPU 的线程与操作系统的线程有何关系?操作系统中的进程和线程是什么关系?
CPU中的线程和操作系统(OS)中的线程即不同,在调度的时候又有些关联.CPU中的线程,我们叫它们Thread,和OS中的线程的名字一样.它来自同步多线程(SMT,Simultaneous Multi ...
- JabRef:将bibtex格式的参考文献导入EndNote的转换软件
我在写小论文的时候,一直用的都是Overleaf在线latex编辑应用: https://www.overleaf.com/login 这个我感觉还是蛮好用的.只需要从期刊或者出版社的官网下载到lat ...
- 转载-公司项目部署交付环境预检查shell脚本
大型项目环境预检查脚本,根据自己实际情况修改脚本中变量,给大家一个思路,转载请注明出处~ 转至:https://www.cnblogs.com/gaohongyu/p/13738526.html #! ...
- LeetCode-061-旋转链表
旋转链表 题目描述:给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例说明请见LeetCode官网. 来源:力扣(LeetCode) 链接:https://leet ...
- elasticsearch高亮之词项向量
一.什么是词项向量 词项向量(term vector)是有elasticsearch在index document的时候产生,其包含对document解析过程中产生的分词的一些信息,例如分词在字段值中 ...
- tensorflow源码解析之common_runtime-direct_session
目录 核心概念 direct_session direct_session.h direct_session.cc 1. 核心概念 读过之前文章的读者应该还记得,session是一个执行代理.我们把计 ...
- Linux——vi命令详解
转载 Linux--vi命令详解 原文链接:https://blog.csdn.net/cyl101816/article/details/82026678 vi编辑器是所有Unix及Linux系 ...
- w10环境vs2017,vs2019配置Opengl快捷方法
最近,计算机图形学老师向我们布置了任务,配置自己的opengl.百度之后我发现很多教程和方法尝试之后,我发现一种简单的方法来分享给大家. 首先我的软件配置是w10专业版系统+Visual Stdio ...
- VuePress 博客优化之增加 Valine 评论功能
前言 在 <一篇带你用 VuePress + Github Pages 搭建博客>中,我们使用 VuePress 搭建了一个博客,最终的效果查看:TypeScript 中文文档. 本篇讲讲 ...