简析ThreadLocal原理及应用

原创: 东晨雨 JAVA万维猿圈 4月17日

ThreadLocal的源码加上注释不超过八百行,源码结构清晰,代码也比较简洁。ThreadLocal可以说是Java中解决多线程数据共享问题方案中的一股清流,该方案为每个线程分配一个独立的变量副本,各个线程之间的变量互不干扰。下面一起来看看吧:

预计阅读时间:5分钟

ThreadLocal的定义与理解

定义和特点:

ThreadLocal顾名思义可以理解为线程本地变量,ThreadLocal将变量的各个副本值保存在各个线程Thread,Thread对象实例采用ThreadLocalMap数据结构来存储副本值。每个线程往这个ThreadLocal中读写是线程隔离,一种将可变数据通过每个线程有自己的独立副本从而实现线程封闭的机制。

适用场景:

(1)  当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值;

(2)  适用于资源共享但不需要维护状态的情况,也就是一个线程对资源的修改,不影响另一个线程的运行;

(3) 基于ThreadLocal实现线程安全是采用"空间换时间",synchronized顺序执行是"时间换取空间"。

ThreadLocal方法及使用示例:

ThreadLocal与其内部类ThreadLocalMap以及线程类Thread联系紧密,为了分析ThreadLocal类的工作原理,先介绍该类的所有方法(JDK 1.8):

该类的核心方法包括4个

(1) protected T initialValue()

(2) public T get()

  1. 先获取当前线程的thread对象,再获取thread对象的threadLocalMap对象,然后根据当前的threadLocal对象取得table数组对应下标的Entry对象;

  2. 如果Thread对象的ThreadLocalMap为空的话,就调用setInitialValue方法,该方法初始化map并且放入null ( initialValue的返回值为null ),可以通过覆盖该方法修改没有set时的初始值。

(3) public void set( T value)

  1. 先调用Thread类的静态方法获得当前线程的Thread对象,每个线程对应的Thread对象都有一个ThreadLocalMap对象的引用;

  2. 获得当前线程的ThreadLocalMap对象;

  3. 如果不为空就调用set方法,如果为空就调用createMap方法,传入参数为ThreadLocalMap为空的Thread对象和T类型的firstValue。

(4) public void remove()

  1. 先获取当前线程的Map对象;

  2. 调用Map的remove方法,删除entry。

ThreadLocal使用注意事项

1、ThreadLoca对象是一个弱引用

ThreadLocalMap中的节点Entry继承了WeakReference类,定义了一个类型为Object的value,用于存放塞到ThreadLocal里的值。如果这里使用普通的key-value形式来定义存储结构,实质上就会造成节点的生命周期与线程强绑定,只要线程没有销毁,那么节点在GC分析中一直处于可达状态,没办法被回收,而程序本身也无法判断是否可以清理节点。ThreadLocal对象是一个继承自WeakReference的弱引用,当把ThreadLocal的实例置为空以后,没有任何强引用指向ThreadLocal的实例,所以ThreadLocal的将会被GC回收。生命周期只存活到下次GC前,可降低内存泄漏的风险。

2、ThreadLocal与内存泄漏

ThreadLocal对象是具有弱引用特点,虽然在一定程度上降低了内存泄漏的风险,但是在有线程复用如线程池的场景中,一个线程的寿命很长,大对象长期不被回收影响系统运行效率与安全,那么就存在一条强引用链的关系一直存在:Thread --> ThreadLocalMap-->Entry-->Value,最终造成内存泄漏。

如何避免内存泄漏:

调用ThreadLocal的get()、set()方法时完成后再调用remove方法,将Entry节点和Map的引用关系移除,这样整个Entry对象在GC Roots分析后就变成不可达了,下次GC的时候就可以被回收。

3、哈希冲突怎么解决

ThreadLocalMap中解决哈希冲突的方式并非链表的方式,而是采用线性探测的方式,具体来说,就是简单的步长加1或减1,寻找下一个相邻的位置。

简析ThreadLocal原理及应用的更多相关文章

  1. Java Android 注解(Annotation) 及几个常用开源项目注解原理简析

    不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...

  2. PHP的错误报错级别设置原理简析

    原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...

  3. Java Annotation 及几个常用开源项目注解原理简析

    PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...

  4. [转载] Thrift原理简析(JAVA)

    转载自http://shift-alt-ctrl.iteye.com/blog/1987416 Apache Thrift是一个跨语言的服务框架,本质上为RPC,同时具有序列化.发序列化机制:当我们开 ...

  5. SIFT特征原理简析(HELU版)

    SIFT(Scale-Invariant Feature Transform)是一种具有尺度不变性和光照不变性的特征描述子,也同时是一套特征提取的理论,首次由D. G. Lowe于2004年以< ...

  6. 简析hotjar录屏功能实现原理

    简析hotjar录屏功能实现原理 众所周知,hotjar中录屏功能是其重要的一个卖点,看着很牛X酷炫的样子,今天就简单的分析一下其可能实现(这里只根据其请求加上个人理解分析,并不代表hotjar中真实 ...

  7. 基于IdentityServer4的OIDC实现单点登录(SSO)原理简析

    写着前面 IdentityServer4的学习断断续续,兜兜转转,走了不少弯路,也花了不少时间.可能是因为没有阅读源码,也没有特别系统的学习资料,相关文章很多园子里的大佬都有涉及,有系列文章,比如: ...

  8. Spring系列.@EnableRedisHttpSession原理简析

    在集群系统中,经常会需要将Session进行共享.不然会出现这样一个问题:用户在系统A上登陆以后,假如后续的一些操作被负载均衡到系统B上面,系统B发现本机上没有这个用户的Session,会强制让用户重 ...

  9. ThreadLocal原理简单刨析

    ThreadLocal原理简单刨析 ThreadLocal实现了各个线程的数据隔离,要知道数据是如何隔离的,就要从源代码分析. ThreadLocal原理 需要提前说明的是:ThreadLocal只是 ...

随机推荐

  1. 红帽RHCE培训-课程2笔记内容

    1 kickstart自动安装 已安装系统中,在root下述目录会自动生成kickstart配置文件 ll ~/anaconda-ks.cfg 关键配置元素注释,详见未精简版 创建Kickstart配 ...

  2. [转]Serverless

    说起当前最火的技术,除了最新的区块链,AI,还有一个不得不提的概念是Serverless.Serverless作为一种新型的互联网架构直接或间接推动了云计算的发展,从AWS Lambda到阿里云函数计 ...

  3. Python学习(三)——Python的运算符和数值、字符的类中方法

    Python开发IDE PyCharm,eclipse PyCharm的基础用法 全部选中后 Ctrl+?全部变为注释 运算符 结果为值的运算符 算术运算符: + - * / % // ** 赋值运算 ...

  4. Go之NSQ

    文章引用自 NSQ NSQ是目前比较流行的一个分布式的消息队列,本文主要介绍了NSQ及Go语言如何操作NSQ. NSQ介绍 NSQ是Go语言编写的一个开源的实时分布式内存消息队列,其性能十分优异. N ...

  5. ajax请求ashx跨域问题解决办法

    ajax请求ashx跨域问题解决办法 https://blog.csdn.net/windowsliusheng/article/details/51583566 翻译windowsliusheng  ...

  6. 「ZJOI2008」树的统计

    树剖模板题啊! 这道题的话,最通(jian)俗(dan)易(cu)懂(bao)的解法应该就是树剖了. 加上线段树维护树上路径的最大权值(\(Max\))和路径和(\(sum\)). 至于\(LCT\) ...

  7. centos 6.5 防火墙通过 80 和 3306 端口

    vim /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPU ...

  8. 2_2 3n+1问题

    猜想:对于任意大于1的自然数n,若n为奇数,则将n变为3n+1,否则变为n的一半.经过若干次这样的变换,一定会使n变为1.例如:3→10→5→16→8→4→2→1. 输入n,输出变换的次数.n< ...

  9. hexo 搭建静态博客 + Next 主题配置

    参考手册 HEXO:https://hexo.io/zh-cn/ NEXT:http://theme-next.iissnan.com/ 安装hexo npm install hexo-cli -g ...

  10. 增加phpmyadmin导入文件上限

    一.修改php配置 修改php配置文件,php.ini upload_max_filesize = 100M post_max_size = 100M 一般修改这2个就行了,然后重启wampserve ...