Java中的线程ThreadLocal详细解析

 更新时间:2023年10月26日 09:04:32   作者:buzhbuzh  
这篇文章主要介绍了Java中的线程ThreadLocal详细解析,ThreadLocal是线程本地变量,存储在ThreadLocal里面的数据都是线程安全的,一般ThreadLocal适用的场景多是各个线程间没有变量共享需要的同步问题场景,需要的朋友可以参考下

一 Java中的引用关系

Java中的引用分为了强引用、弱引用、软引用、虚引用

  • 强引用: 垃圾回收的时候,如果内存不足也不会进行垃圾回收,会报out-of-memory异常
  • 弱引用: 垃圾回收的时候,如果内存不够,则数据被回收.
  • 软引用: 垃圾回收的时候,软引用会立刻进行回收
  • 虚引用: 垃圾回收的时候,软引用会立刻进行回收

二 ThreadLocal代码实现

ThreadLocal是线程本地变量,存储在ThreadLocal里面的数据都是 线程安全的.

一般ThreadLocal适用的场景多是各个线程间没有变量共享需要的同步问题场景,比如一个简单的SimpleDateFormat类,该类不是线程安全的,却是有状态的,如果将SimpleDateFormat设置为静态的,所有线程共享,那么就会出现线程安全的问题,其中一个线程修改日期格式为“yyyyMMdd”,然后可能会影响到另外一个需要格式为“yyyy-MM-dd”的线程。但是如果在方法中每次用到的时候都new一个SimpleDateFormat类又太费内存(SimpleDateFormat这种简单的类倒还好,若是一些比较占用资源的比如数据库连接类等,就会让加大整个数据库的压力),这时候采用ThreadLocal为每一个线程保存一份SimpleDateFormat副本,这样既不会说每次调用方法都会生成一个对象,也不会在并发时产生线程同步问题。这就像是在共享一个静态变量和每次使用都new一个对象两者之间的一种折中处理方法。

自己实现的ThreadLocal

在这里插入图片描述

通过一个全局map, key是Thread对象,value是对应存储的数据,这种情况下 如果map不销毁,对应的Thread线程就不发被回收,导致内存泄露

JDK中使用的ThreadLocal

在这里插入图片描述

JDK8中在Thread对象中引用ThreadLocalMap,ThreadLocalMap的生命周期是Thread是同一个生命周期.

ThreadLocalMap的实现

(1) Entry数组实现

在这里插入图片描述

Entry数组是线程中实际存放数据的地方,key是ThreadLocal,是一个弱引用,value是对应存储的值.

为什么ThreadLocalMap#key是一个弱引用

如果外部不使用了ThreadLocal,则对应的数据不应该存储在ThreadLocal中,应该被删除掉,防止内存泄漏

ThreadLocalMap的属性

        private static final int INITIAL_CAPACITY = 16;
    	//存储数据的地方
        private Entry[] table; //
    	//数量
        private int size = 0;
        private int threshold; // Default to 0

ThreadLocal的方法

ThreadLocal#set()方法

在这里插数据入图片描述

(1) 第一步 获取到当前线程的ThreadLocalMap

(2) 第二步 初始化ThreadLocalMap

(3) 第三步 将ThreadLocal作为key,value值作为值,设置到map中

ThreadLocal # get()方法

在这里插入图片描述

方法主要完成两个功能: (1) 完成数据的读取 (2) 将ThreadLocalMap中key为NULL的数据从ThreadLocalMap中删除

ThreadLocalMap中的entry其实是继承的弱引用,如果该弱引用指向的ThreadLocal没有在外部被强引用指向的话,在下次gc的时候就会被回收,那这样的话就会出现ThreadLocalMap中存在key为null的情况,这样的数据对于map来讲是脏数据,这样的脏数据没有用,却一直占用着map的存储空间,这其实就是一种内存泄漏,所以需要来释放掉这些空间

三 ThreadLocalMap的内存泄漏问题

如果ThreadLocal无强引用进行应用,则在垃圾回收的时候会把这个key进行回收.

这个时候,因为线程还存活,所以ThreadLocalMap依旧存在,但是key为null,这个 key对应的value就无法被访问到了,造成内存泄漏.

JDK团队自己的解决办法

调用get()、set()方法的时候,自动清理掉ThreadLocalMap中key为null的数据

开发者的解决办法 使用ThreadLocal后,调用ThreadLocal

到此这篇关于Java中的线程ThreadLocal详细解析的文章就介绍到这了,更多相关Java的ThreadLocal内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java生成由时间组成的订单号方式

    Java生成由时间组成的订单号方式

    这篇文章主要介绍了Java生成由时间组成的订单号方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • 浅谈java 中文件的读取File、以及相对路径的问题

    浅谈java 中文件的读取File、以及相对路径的问题

    今天小编就为大家分享一篇浅谈java 中文件的读取File、以及相对路径的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • Eclipse中自动添加注释(两种)

    Eclipse中自动添加注释(两种)

    本文主要介绍了Eclipse中自动添加注释的两种方法。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Java Socket+多线程实现多人聊天室功能

    Java Socket+多线程实现多人聊天室功能

    这篇文章主要为大家详细介绍了Java Socket+多线程实现多人聊天室功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • Java中常见字符串拼接九种方式详细例子

    Java中常见字符串拼接九种方式详细例子

    这篇文章主要给大家介绍了关于Java中常见字符串拼接的九种方式,字符串拼接是我们在Java代码中比较经常要做的事情,就是把多个字符串拼接到一起,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • 如何理解SpringMVC

    如何理解SpringMVC

    Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发
    2021-06-06
  • Java的线程与进程以及线程的四种创建方式

    Java的线程与进程以及线程的四种创建方式

    这篇文章主要为大家详细介绍了Java的线程与进程以及线程的四种创建方式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • Java 自定义错误类示例代码

    Java 自定义错误类示例代码

    以下是对Java中自定义错误类的示例代码进行了介绍。需要的朋友可以过来参考下
    2013-08-08
  • IDEA配置JavaFX全过程

    IDEA配置JavaFX全过程

    从Java11起,Java不再内置JavaFX,在Java17项目中,需手动配置开发环境,添加JavaFX库路径,并设置运行参数指向本地路径
    2025-09-09
  • spring boot 异步线程池的使用详解

    spring boot 异步线程池的使用详解

    本文介绍了如何在SpringBoot项目中配置异步线程池,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2026-04-04

最新评论