ThreadLocal的用处

ThreadLocal是一个多线程的辅助工具类,目的是方便开发者维护多线程中的共享变量。我们知道如果我们想要在一个线程中一直访问一个变量或者在线程上下文中保存一个变量,我们要么将该变量声明为static静态,要么就在每一步函数调用中均传入该变量。这两种方式,static方式不能解决每个线程同时分别持有的问题。每一步函数传入对代码的侵入性过高。

所以ThreadLocal实际的使用效果就是以线程维度,让每个线程拥有了一个自己的上下文变量池,防止大量的静态声明。这也是为什么它并不在juc并发包里的原因。

ThreadLocal的实现

通过上述TheadLocal的用处和它解决的问题,我们可以马上想到一个很简单的实现来补充static实现的缺点:我们可以通过定义一个static的Map,其中key为线程或线程id,value为需要保存的变量。

TheadLocal的实际实现方法也类似,不过在其中进行了一定改进:

  1. TheadLocal实现体系中,由Thead本身持有该Map,其中Key为TheadLocal,value为值。
  2. TheadLocal本身仅通过同包可以访问的特性,提供了一系列访问Thead中的Map的Api。

ThreadLocal防止内存泄露

我们知道,TheadLocal这种实现体系下,Thread会持有一个Map,并且该Map中会大量使用TheadLocal作为key,Map引用关系默认是强引用。在线程池或连接池这种会对线程进行复用的场景下,为了防止TheadLocal被强引用导致一直不能被回收,所以Thead中对TheadLocal的维护Map使用的是一个简单实现的WeakReferenceMap。该Map有以下特点:

  1. 该Map的哈希冲突使用跳跃式处理,而不是HashMap中的桶。原因应该是把该空间当做栈来思考的话,使用跳跃式可以减少更多的空间分配,并且更好的利用cpu缓存。
  2. 该Map的Entry,由继承了WeakReference的Entry实现,该Entry本身为TheadLocal的一个弱引用,当TheadLocal的强引用失去,被gc回收后。该Map在其各方法中都增加了清理Map节点的步骤,根据该弱引用对应的弱引用回收队列中的节点,清理Map中对应的键值对。

ThreadLocal为什么会内存泄露

这点其实应该放在上面那点之前说,但是这个确实也困扰了比较久,钻了牛角尖,一直没有明白。

我们日常中一般使用TheadLocal的方式都如下,比如使用一个Util类来维护请求的TraceId,进行链路追踪的效果:

public class TraceIDUtils {
private static final ThreadLocal<String> SEQUENCE_ID = new ThreadLocal<String>();
}

那么我们会发现,该TheadLocal对象,本身就是一个static声明,永远存在来源于该类的强引用,那么该TheadLocal本身就不会被回收,Thead中的Map是否使用弱引用好像毫无意义。

当时也是思考了比较久,后面才发现钻了牛角尖,当时大牛们设计出来,应该是考虑类似情况:

public class Test {
ThreadLocal<String> threadLocal;
public void run(){
this.threadLocal = new ThreadLocal<>();
this.threadLocal.set("abc");
//do something
//……
//end
}
public static void main(String[] args) throws Exception {
new Test().run();
}
}

我们现在当然知道,不使用static定义,肯定是不合适的,但是Java的大牛们作为Api的设计者,肯定是要考虑到其他人在任何情况下使用该工具都应是安全的。而在这种使用方式下,在线程被销毁前,显然如果线程中的Map对该TheadLocal为强引用,那么在该方法执行完毕后该方法内的强引用消失后,依旧在Map上会直接造成内存泄露。

这也能使人明白为什么Java不选择在TheadLocal中维护一个以Thead为Key的Map来实现。

Java基础:ThreadLocal及其原理的更多相关文章

  1. 【原理】Java的ThreadLocal实现原理浅读

    当前线程的值传递,ThreadLocal 通过ThreadLocal设值,在线程内可获取,即时获取值时在其它Class或其它Method. public class BasicUsage { priv ...

  2. Java基础之Synchronized原理

    思维导图svg: https://note.youdao.com/ynoteshare1/index.html?id=eb05fdceddd07759b8b82c5b9094021a&type ...

  3. 【Java基础】HashMap原理详解

    哈希表(hash table) 也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中Has ...

  4. java基础-注解Annotation原理和用法

    在很多java代码中都可以看到诸如@Override.@Deprecated.@SuppressWarnings这样的字符,这些就是注解Annotation.注解最早在jdk5中被引入,现在已经成为j ...

  5. Java基础--ThreadLocal

    Java中的ThreadLocal 可以看做以线程标识为key的Map,在多线程开发中使用非常方便. 示例 class ThreadEnv { // 用匿名内部类覆盖ThreadLocal的initi ...

  6. Java基础 | Stream流原理与用法总结

    Stream简化元素计算: 一.接口设计 从Java1.8开始提出了Stream流的概念,侧重对于源数据计算能力的封装,并且支持序列与并行两种操作方式:依旧先看核心接口的设计: BaseStream: ...

  7. JAVA基础之——Thrift原理及应用

    1 是什么 是为了解决facebook系统中各系统间大数据量的传输通信,以及系统之间语言环境不同需要跨平台的问题. 是一种实现RPC的软件框架,自定义IDL(Interface description ...

  8. Java基础之Volatile原理

    原文链接: http://www.aoaoyi.com/archives/956.html 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据 的读取和写入.由于程序运 ...

  9. Java基础之HashMap原理分析(put、get、resize)

    在分析HashMap之前,先看下图,理解一下HashMap的结构 我手画了一个图,简单描述一下HashMap的结构,数组+链表构成一个HashMap,当我们调用put方法的时候增加一个新的 key-v ...

  10. Java基础之LinkedHashMap原理分析

    知识准备HashMap 我们平时用LinkedHashMap的时候,都会写下面这段 LinkedHashMap<String, Object> map = new LinkedHashMa ...

随机推荐

  1. Java线程状态介绍

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11867086.html Java 线程状态介绍: Java官方文档中对Java线程的几种状态做 ...

  2. rsync 远程同步部署——上下行同步

    rsync 远程同步部署--上下行同步 1.rsync (Remote Sync,远程同步) : 是一个开源的快速备份工具,可以在不同主机之间镜像同步整个目录树,支持增量备份,并保持链接和权限,且采用 ...

  3. 【论文阅读笔记】-针对RSA的短解密指数的密码学分析(Cryptanalysis of Short RSA Secret Exponents)

    目录 1. 介绍 polynomially larger 2. 连分数背景知识 3. 连分数算法 4. 连分数算法在RSA中的应用 5. 例子 6. 对RSA连分数攻击的反制 7. 对于攻击的改进 8 ...

  4. js实现网页回弹小球效果

    直接上效果图 运行页面会首先弹出一个输入框,询问用户想要产生的小球数量,随后后台就会产生指定数量的小球,在页面中来回跳动,触碰到页面边框时,就会回弹,且产生的小球颜色随机,小球在页面中的位置随机,小球 ...

  5. Lesson11——NumPy 位运算

    NumPy 教程目录 Lesson11--NumPy 位运算 NumPy "bitwise_" 开头的函数是位运算函数. NumPy 位运算包括以下几个函数: 函数 描述 bitw ...

  6. Linux系统安装(CentOS-7)详细操作步骤

    Linux系统安装(CentOS-7)详细操作步骤 一.创建虚拟机 首先创建一个虚拟机,然后才能在虚拟机里面安装系统. 第一步,创建虚拟机的向导 第二步,兼容性默认即可. 第三步,我们等创建完虚拟机后 ...

  7. 书写高质量sql的一些建议

    It's better to light a candle than to curse the darkness 老生常谈的不要使用select * 如果硬要使用select *,那么就请忍受一下以下 ...

  8. 【Java分享客栈】我为什么极力推荐XXL-JOB作为中小厂的分布式任务调度平台

    前言   大家好,我是福隆苑居士,今天给大家聊聊XXL-JOB的使用.   XXL-JOB是本人呆过的三家公司都使用到的分布式任务调度平台,前两家都是服务于传统行业(某大型移动基地和某大型电网),现在 ...

  9. 攻防世界之Web_php_rce

    题目: ========================================================================== 解题思路: 1.这题主要考查ThinkPH ...

  10. 【转】VMWare中的Host-only、NAT、Bridge

    背景:A是本机,A1,A2是虚拟机,B是外部联网的机器 host-only(主机模式): A可以和A1,A2互通,A1,A2 -> B不可以,B -> A1,A2不行 bridge(桥接模 ...