返回顶部
首页 > 资讯 > 精选 >Java多线程之ThreadLocal的原理是什么
  • 877
分享到

Java多线程之ThreadLocal的原理是什么

2023-07-06 00:07:53 877人浏览 独家记忆
摘要

今天小编给大家分享一下Java多线程之ThreadLocal的原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、什

今天小编给大家分享一下Java多线程之ThreadLocal的原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    1、什么是 ThreadLocal:

    ThreadLocal,即线程本地变量,如果你创建了一个变量,那么访问这个变量的每个线程都会有这个变量的本地拷贝,多个线程操作这个变量的时候,实际操作自己本地内存里面的变量,从而起到线程隔离的作用,避免了线程安全问题

    ThreadLocal 适用于无状态,副本变量独立后不影响业务逻辑的高并发场景,如果业务逻辑强依赖于变量副本,则不适合用 ThreadLocal 解决,需要另寻解决方案

    应用场景:

    数据库连接池会话管理中使用

    2、ThreadLocal 的数据结构

    jdk8 中,每个线程 Thread 内部都维护了一个 ThreadLocalMap 的数据结构,ThreadLocalMap 中有一个由内部类 Entry 组成的 table 数组,Entry 的 key 就是线程的本地化对象 ThreadLocal,而 value 则存放了当前线程所操作的变量副本。每个 ThreadLocal 只能保存一个副本 value,并且各个线程的数据互不干扰,如果想要一个线程保存多个副本变量,就需要创建多个ThreadLocal。

    一个 ThreadLocal 的值,会根据线程的不同,分散在 N 个线程中,所以获取 ThreadLocal 的 value,有两个步骤:

    第一步,根据线程获取 ThreadLocalMap

    第二步,根据自身从 ThreadLocalMap 中获取值,所以它的 this 就是 Map 的 Key

    当执行 set() 方法时,其值是保存在当前线程的 ThreadLocal 变量副本中
    当执行get() 方法中,是从当前线程的 ThreadLocal 的变量副本获取。

    所以对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了线程的隔离,互不干扰。

    Java多线程之ThreadLocal的原理是什么

    3、ThreadLocal 的核心方法:

    ThreadLocal 对外暴露的方法有4个:

    initialValue()方法:返回为当前线程初始副本变量值。
    2.get()方法:获取当前线程的副本变量值。
    3.set()方法:保存当前线程的副本变量值。
    4.remove()方法:移除当前前程的副本变量值

     1、set()方法:

    // 设置当前线程对应的ThreadLocal值public void set(T value) {    Thread t = Thread.currentThread(); // 获取当前线程对象    ThreadLocalMap map = getMap(t);    if (map != null) // 判断map是否存在        map.set(this, value);         // 调用map.set 将当前value赋值给当前threadLocal。    else        createMap(t, value);        // 如果当前对象没有ThreadLocalMap 对象。        // 创建一个对象 赋值给当前线程} // 获取当前线程对象维护的ThreadLocalMapThreadLocalMap getMap(Thread t) {    return t.threadLocals;}// 给传入的线程 配置一个threadlocalsvoid createMap(Thread t, T firstValue) {    t.threadLocals = new ThreadLocalMap(this, firstValue);}

    执行流程:

    获得当前线程,根据当前线程获得 map。
    2.如果 map 不为空,则将参数设置到 map 中,当前的 Threadlocal 作为 key。
    3.如果 map 为空,则给该线程创建 map,设置初始值。

     2、get()方法:

    public T get() {    Thread t = Thread.currentThread();//获得当前线程对象    ThreadLocalMap map = getMap(t);//线程对象对应的map    if (map != null) {        ThreadLocalMap.Entry e = map.getEntry(this);// 以当前threadlocal为key,尝试获得实体        if (e != null) {            @SuppressWarnings("unchecked")            T result = (T)e.value;            return result;        }    }    // 如果当前线程对应map不存在    // 如果map存在但是当前threadlocal没有关连的entry。    return setInitialValue();} // 初始化private T setInitialValue() {    T value = initialValue();    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null)        map.set(this, value);    else        createMap(t, value);    return value;}

    执行流程:

    (1)先尝试获得当前线程,再根据当前线程获取对应的 map
    (2)如果获得的 map 不为空,以当前 threadlocal 为 key 尝试获得 entry
    (3)如果 entry 不为空,返回值。
    (4)如果 2 跟 3 出现无法获得,则通过 initialValue 函数获得初始值,然后给当前线程创建新 map

     3、remove()方法:

    public void remove() {    ThreadLocalMap m = getMap(Thread.currentThread());    if (m != null)        m.remove(this);}

    执行流程:

    首先尝试获取当前线程,然后根据当前线程获得map,从map中尝试删除enrty。

    4、initialValue() 方法:

    protected T initialValue() {    return null;}

    执行流程:

    (1)如果没有调用 set() 直接 get(),则会调用此方法,该方法只会被调用一次,
    (2)默认返回一个缺省值null,如果不想返回null,可以Override 进行覆盖。

    4、ThreadLocal 的哈希冲突的解决方法:线性探测

    HashMap 不同,ThreadLocalMap 结构中没有 next 引用
    ThreadLocalMap 中解决哈希冲突的方式并非链表的方式,而是采用线性探测的方式,当发生哈希冲突时就将步长加1或减1,寻找下一个相邻的位置

    流程说明:

    根据 ThreadLocal 对象的 hash 值,定位到 table 中的位置 i;

    如果当前位置是 null,就初始化一个 Entry 对象放在位置 i 上;

    如果位置 i 已经有 Entry 对象了,如果这个 Entry 对象的 key 与即将设置的 key 相同,那么重新设置 Entry 的 value;

    如果位置 i 的 Entry 对象和 即将设置的 key 不同,那么寻找下一个空位置;

    5、ThreadLocal 的内存泄露:

    在使用 ThreadLocal 时,当使用完变量后,必须手动调用 remove() 方法删除 entry 对象,否则会造成 value 的内存泄露,严格来说,ThreadLocal 是没有内存泄漏问题,有的话,那也是忘记执行 remove() 引起的

    内存泄露的根本原因在于 ThreadLocalMap 的生命周期与当前线程 CurrentThread 的生命周期相同,且 ThreadLocal 使用完没有进行手动删除导致的

    ThreadLocal 的内存泄露与强弱引用无关,那么为什么还要用弱引用呢?

    (1)Entry 中的 key(Threadlocal)是弱引用,目的是将 ThreadLocal 对象的生命周期跟线程周期解绑,用 WeakReference 弱引用关联的对象,只能生存到下一次垃圾回收之前,GC发生时,不管内存够不够,都会被回收。

    (2)当我们使用完 ThreadLocal,而 Thread 仍然运行时,即使忘记调用 remove() 方法, 弱引用也会比强引用多一层保障:当 GC 发生时,弱引用的 ThreadLocal 被收回,那么 key 就为 null 了。而 ThreadLocalMap 中的 set()、get() 方法,会针对 key == null (也就是 ThreadLocal 为 null) 的情况进行处理,如果 key == null,则系统认为 value 也应该是无效了应该设置为 null,也就是说对应的 value 会在下次调用 ThreadLocal 的 set()、get() 方法时,执行底层 ThreadLocalMap 中的 expungeStaleEntry() 方法进行清除无用的 value,从而避免内存泄露。

    6、ThreadLocal 的应用场景:

    (1)Hibernate 的 session 获取:每个线程访问数据库都应当是一个独立的 session 会话,如果多个线程共享同一个 session 会话,有可能其他线程关闭连接了,当前线程再执行提交时就会出现会话已关闭的异常,导致系统异常。

    使用 ThreadLocal 的方式能避免线程争抢session,提高并发安全性。

    (2)spring事务管理:事务需要保证一组操作同时成功或失败,意味着一个事务的所有操作需要在同一个数据库连接上,Spring 采用 Threadlocal 的方式,来保证单个线程中的数据库操作使用的是同一个数据库连接,同时采用这种方式可以使业务层使用事务时不需要感知并管理 connection 对象,通过传播级别,巧妙地管理多个事务配置之间的切换,挂起和恢复

    7、如果想共享线程的 ThreadLocal 数据怎么办 ?

    使用 InheritableThreadLocal 可以实现多个线程访问 ThreadLocal 的值

    我们在主线程中创建一个 InheritableThreadLocal 的实例,然后在子线程中得到这个InheritableThreadLocal实例设置的值。

    private void test() {    final ThreadLocal threadLocal = new InheritableThreadLocal();       threadLocal.set("主线程的ThreadLocal的值");    Thread t = new Thread() {            @Override            public void run() {                  super.run();                  Log.i( "我是子线程,我要获取其他线程的ThreadLocal的值 ==> " + threadLocal.get());            }      };            t.start(); }

    8、为什么一般用 ThreadLocal 都要用 static?

    ThreadLocal 能实现线程的数据隔离,不在于它自己本身,而在于 Thread 的 ThreadLocalMap,所以,ThreadLocal 可以只实例化一次,只分配一块存储空间就可以了,没有必要作为成员变量多次被初始化。

    以上就是“Java多线程之ThreadLocal的原理是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: Java多线程之ThreadLocal的原理是什么

    本文链接: https://lsjlt.com/news/356367.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Java多线程之ThreadLocal的原理是什么
      今天小编给大家分享一下Java多线程之ThreadLocal的原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、什...
      99+
      2023-07-06
    • Java多线程之ThreadLocal原理总结
      目录1、什么是 ThreadLocal:2、ThreadLocal 的数据结构:3、ThreadLocal 的核心方法: 1、set()方法: 2、get()方法...
      99+
      2023-05-15
      Java多线程ThreadLocal 原理 Java多线程 ThreadLocal 原理
    • Java多线程 ThreadLocal原理解析
      目录1、什么是ThreadLocal变量2、ThreadLocal实现原理3、内存泄漏问题4、使用场景1)存储用户Session2)解决线程安全的问题3)使用ThreadLocal重...
      99+
      2024-04-02
    • Java中ThreadLocal线程变量的实现原理是什么
      这篇文章主要介绍了Java中ThreadLocal线程变量的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java中ThreadLocal线程变量的实现原理是什么文章都会有所收获,下面我们一起来看...
      99+
      2023-07-02
    • Java多线程之ThreadLocal浅析
      目录介绍什么是ThreadLocal?ThreadLocal 的作用是什么?如何使用ThreadLocal如何创建一个ThreadLocal实例ThreadLocal的实现原理Thr...
      99+
      2023-05-17
      Java多线程 Java ThreadLocal 多线程ThreadLocal
    • java多线程的原理是什么
      本篇内容介绍了“java多线程的原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!本教程操作环境:windows7系统、java10版...
      99+
      2023-06-30
    • java中多线程的原理是什么
      java中多线程的原理是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。java基本数据类型有哪些Java的基本数据类型分为:1、整数类型,用来表示整数的数据...
      99+
      2023-06-14
    • java 中多线程的原理是什么
      今天就跟大家聊聊有关java 中多线程的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1.基本概念程序、进程、线程程序(program)是为完成特定任务、用某种语言编写的一...
      99+
      2023-06-20
    • Java中多线程同步的原理是什么
      Java中多线程同步的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、线程的先来后到我们来举一个Dirty的例子:某餐厅的卫生间很小,几乎只能容纳一个人如厕。为了保...
      99+
      2023-06-17
    • Java中ThreadLocal线程变量的实现原理
      目录ThreadLocal是什么ThreadLocal实现原理分析ThreadLocal内存泄漏问题ThreadLocal是什么 ThreadLocal 使得我们可以创建线程私有的变...
      99+
      2024-04-02
    • Java中ThreadLocal的用法和原理是什么
      这篇文章主要介绍“Java中ThreadLocal的用法和原理是什么”,在日常操作中,相信很多人在Java中ThreadLocal的用法和原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中Th...
      99+
      2023-07-06
    • Java多线程之Park和Unpark原理
      目录一、基本使用二、特点三、park unpark 原理四、park/unpark 原理总结一、基本使用 它们是 LockSupport 类中的方法 // 暂停当前线程 Lock...
      99+
      2024-04-02
    • Java中ThreadLocal的原理是什么及怎么使用
      这篇文章主要介绍“Java中ThreadLocal的原理是什么及怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal的原理是什么及怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Jav...
      99+
      2023-07-06
    • ThreadLocal的set方法原理是什么
      这篇文章主要介绍了ThreadLocal的set方法原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇ThreadLocal的set方法原理是什么文章都会有所收获,下面我们一起来看看吧。前沿知识Threa...
      99+
      2023-07-05
    • Java Socket线程的设计原理是什么
      这篇文章主要讲解了“Java Socket线程的设计原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java Socket线程的设计原理是什么”吧!Java Socket线程我们经常...
      99+
      2023-06-17
    • Java多线程之Park和Unpark原理分析
      这篇文章主要介绍了Java多线程之Park和Unpark原理分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适...
      99+
      2023-06-14
    • Java多线程揭秘之synchronized工作原理
      目录一.特性二.加锁过程(锁升级/锁膨胀)1.无锁状态2.偏向锁3.轻量级锁4.重量级锁5.总结三.锁优化1.锁消除2.锁粗化在学习本篇文章时,如果有不太懂的地方,大家也可以先看看博...
      99+
      2024-04-02
    • Java多线程之什么是Worker Thread模式
      本篇内容主要讲解“Java多线程之什么是Worker Thread模式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多线程之什么是Worker Thread模式”吧!一.Worker T...
      99+
      2023-06-25
    • Java线程池实现原理是什么
      这篇文章主要讲解了“Java线程池实现原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java线程池实现原理是什么”吧!一、线程池参数corePoolSize(必填):核心线程数。m...
      99+
      2023-06-28
    • java线程之死锁产生的原因是什么
      这篇文章主要讲解了“java线程之死锁产生的原因是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java线程之死锁产生的原因是什么”吧!一、什么是死锁死锁是指两个或两个以上的进程在执行过...
      99+
      2023-06-30
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作