简析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. Qt: 释放窗口资源

    1. 对于使用指针,使用new创建的窗口,当然可以使用delete显示的释放其占用的资源: Widget *w = new Widget(); delete w;   2. 对于使用指针,使用new创 ...

  2. opencv:绘制图像直方图

    #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...

  3. map遍历删除

    List<Object> orderManageList = cacheService.values(key); Iterator<Object> it=orderManage ...

  4. 【MySQL】库的操作

    "SQL语言主要用于存取数据.查询数据.更新数据和管理关系数据库系统,SQL语言由IBM开发. SQL语言分为3种类型: DDL语句 数据库定义语言:数据库.表.视图.索引.存储过程,例如C ...

  5. @media screen 自适应笔记

    在css中使用@media screen 通过检索宽度 对应改变html中class的css属性. 1280分辨率以上(大于1200px) @media screen and (min-width:1 ...

  6. VUE项目部署公网ip和端口以及使用域名访问配置

    前提是已经配置好了相应的外网和内网端口的映射 一.公网ip和端口配置 在vue项目启动之前对项目下:项目名/config/index.js 文件进行修改 原来的内容为:(位置在index.js的第16 ...

  7. XMPPFramework 框架

    https://blog.csdn.net/qq_29846663/article/details/70170646 2017-04-14 11:37:02 于海明 阅读数 478更多 分类专栏: i ...

  8. Bugku-CTF加密篇之easy_crypto(0010 0100 01 110 1111011 11 11111 010 000 0 001101 1010 111 100 0 001101 01111 000 001101 00 10 1 0 010 0 000 1 01111 10 11110 101011 1111101)

    easy_crypto 0010 0100 01 110 1111011 11 11111 010 000 0 001101 1010 111 100 0 001101 01111 000 00110 ...

  9. ZOJ007 Numerical Summation of a Series(纯数学)

    #include<bits/stdc++.h> using namespace std; int main() { double i; double k; for(i=0.000;i-2. ...

  10. JS打开浏览器新窗口

    window.open(URL,name,features,replace); 参数 描述 URL 一个可选的字符串,声明了要在新窗口中显示的文档的 URL.如果省略了这个参数,或者它的值是空字符串, ...