简析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. 2019年小结&2020年展望

    每篇一句 If you want love, then this is it. This is real life. It's not perfect but it's real. --Before ...

  2. 从0到1了解 CI/CD

    现代软件开发的需求加上部署到不同基础设施的复杂性使得创建应用程序成为一个繁琐的过程.当应用程序出现规模性增长,开发团队人员变得更分散时,快速且不断地生产和发布软件的流程将会变得更加困难.为了解决这些问 ...

  3. java平衡二叉树AVL数

    平衡二叉树(Balanced Binary Tree)具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树 右旋:在插入二叉树的时候,根节点的右侧高 ...

  4. 基于G6画个xmind出来

    公司产品因为业务发展,出现了一个新的需求:需要去实现知识库的层级知识展示,展示效果通过树图来实现,具体的展示形式可见下图: 其中有几个需要注意点: 节点上的详情icon可以点击,点击展开关闭详情 节点 ...

  5. pikachu-搜索型注入 #手工注入

    1.搜索型注入漏洞产生的原因: 在搭建网站的时候为了方便用户搜索该网站中的资源,程序员在写网站脚本的时候加入了搜索功能,但是忽略了对搜索变量的过滤,造成了搜索型注入漏洞,又称文本框注入. 2.搜索型注 ...

  6. 【代码审计】XDCMS 报错注入

    审计的都是之前很老的一些的CMS,把学习的过程分享出来,如果有正在和我一起学习的兄弟们,希望看到文章之后会有所收获 ------------------------------------------ ...

  7. 吴裕雄--天生自然Numpy库学习笔记:NumPy 切片和索引

    ndarray 数组可以基于 0 - n 的下标进行索引,切片对象可以通过内置的 slice 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组. import ...

  8. 判断一个数组是否包含一个指定的值 includes-ES6

    var array1 = [1, 2, 3]; console.log(array1.includes(2));  // trueconsole.log(array1.includes(2, 5)); ...

  9. 命令关闭tomcat

    1.netstat -ano|findstr 8080(默认端口为8080) 2. taskkill /F /PID 17652 关闭后面的进程号(17652),直到输入上面第三个命令查不到占用808 ...

  10. mcast_block_source函数

    #include <errno.h> #include <sys/socket.h> #define SA struct sockaddr int mcast_block_so ...