广告
返回顶部
首页 > 资讯 > 前端开发 > VUE >java中InheritableThreadLocal异步传递数据的实现原理
  • 507
分享到

java中InheritableThreadLocal异步传递数据的实现原理

2024-04-02 19:04:59 507人浏览 薄情痞子
摘要

本篇内容主要讲解“java中InheritableThreadLocal异步传递数据的实现原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java中Inher

本篇内容主要讲解“java中InheritableThreadLocal异步传递数据的实现原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java中InheritableThreadLocal异步传递数据的实现原理”吧!

在Java中,一个Java线程就是一个操作系统线程,创建一个线程需要通过new  Thread创建,由JVM为Thread绑定操作系统线程,即便是使用线程池,也需要通过new Thread创建线程。

Thread类有两个ThreadLocal字段:

public class Thread implements Runnable {     ThreadLocal.ThreadLocalMap threadLocals = null;     ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; }

InheritableThreadLocal是ThreadLocal的子类,本质上就是一个ThreadLocal。

在Thread类中,threadLocals与inheritableThreadLocals都是线程对象私有的,只能通过当前线程对象写入和获取数据,只是Thread会将写入inheritableThreadLocals的数据传递给子线程的inheritableThreadLocals。

当我们往ThreadLocal或者InheritableThreadLocal写入数据时,写入过程为:

  • 1、ThreadLocal或者InheritableThreadLocal先调用Thread#currentThread静态方法获取当前线程的Thread对象;

  • 2、获取Thread对象的threadLocals或者inheritableThreadLocals;

  • 3、将ThreadLocal或者InheritableThreadLocal对象作为key,将数据写入到当前Thread对象的threadLocals或者inheritableThreadLocals字段中。

因此,Thread的threadLocals与inheritableThreadLocals的key是ThreadLocal或者InheritableThreadLocal实例,value是写入的数据。

关于threadLocals我在前面一篇《反向理解ThreadLocal,或许这样更容易理解》已经详细介绍过了,本篇重点分析inheritableThreadLocals是如何传递给子线程的。

默认情况下,当我们使用new  Thread()创建一个线程时,在Thread的构造方法中会通过Thread#currentThread获取当前线程,将当前线程作为新创建线程的父线程,所以就有了父子线程关系。

无论使用哪个重载的构造方法创建Thread,都会在构造方法中调用init方法完成初始化为Thread字段赋值,而init方法中有这样一段代码:

private void init(ThreadGroup g, Runnable target, String name,                       long stackSize, AccessControlContext acc,                       boolean inheritThreadLocals) {         ......         if (inheritThreadLocals && parent.inheritableThreadLocals != null)             this.inheritableThreadLocals =                 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        ...... }

在init方法中,由于inheritThreadLocals参数默认为true,所以只要父线程的inheritableThreadLocals字段不为空,就copy一份父线程的inheritableThreadLocals给当前创建的线程对象,这就实现了将父线程的inheritableThreadLocals存储的数据传递给子线程。

使用InheritableThreadLocal我们不得不考虑的问题:内存泄漏。

ThreadLocal.ThreadLocalMap使用数组存储元素,与HashMap不同,它通过开放定址法解决hash冲突,不存在链表,通过动态扩容数组可无限存储元素,数组元素的类型为Entry。

当我们往ThreadLocal.ThreadLocalMap写入一个key-value时,ThreadLocalMap把key和value包装成一个Entry,并通过key的hashcode值计算索引值,将Entry放到数组中。

ThreadLocal.ThreadLocalMap.Entry类的源码如下:

static class Entry extends WeakReference<ThreadLocal<?>> {    Object value;    Entry(ThreadLocal<?> k, Object v) {        super(k);        value = v;    } }

虽然key为弱引用的ThreadLocal,当ThreadLocal释放时,Entry的key变为null,但由于value还在,如果Thread不释放,那么Entry也就不会被垃圾收集器回收。

但如果线程是临时创建的,在方法中创建且没有被其它地方引用,当线程执行完成时就会被JVM销毁,在线程实际退出之前由JVM调用线程的exit方法给线程对象完成清理。exit方法部分源码如下。

private void exit() {     ......     threadLocals = null;     inheritableThreadLocals = null;     ...... }

因此,只要Thread对象的exit方法被调用,就不会存在内存泄漏问题。只要线程用完就销毁,那么使用InheritableThreadLocal,在子线程中不需要调用InheritableThreadLocal的remove方法也不会存在内存泄漏的可能。

比如我们在项目中使用InheritableThreadLocal实现将Session传递给子线程:

@GetMapping("/test") public SsoUser test() {     // 获取登录用户     SsoUser ssoUser = SsoUserManager.curLoggedUser();     System.out.println(ssoUser.getUserCode());     // 支持子线程传递     new Thread(() -> {         try {             Thread.sleep(100);             SsoUser ssoUser2 = SsoUserManager.curLoggedUser();             System.out.println(ssoUser2.getUserCode());         } catch (InterruptedException e) {         }     }).start();     return ssoUser; }

在此案例中,由于子线程只是临时创建的,所以我们不需要在子线程中调用InheritableThreadLocal的remove方法,只需要在父线程调用一次remove方法,因为Tomcat的work线程是不会在一次请求结束后就销毁的。

现在我们已经知道了InheritableThreadLocal是如何实现将数据传递给子线程的,思考题的答案也就有了一半:由于InheritableThreadLocal只能将线程上下文传递给当前线程创建的子线程,所以只有线程池中的线程是由当前线程创建的才能够传递。

但要知道另一半答案我们还需要从线程池中寻找。

使用不同参数构建的线程池不同,常见的有单线程的线程池、只有固定数量核心线程的线程池、有固定数量核心线程和非核心线程的线程池、只有非核心线程的线程池。

线程池的几个构造参数说明如下:

  • corePoolSize:核心线程数,不会被释放的线程数量(设置allowCoreThreadTimeOut为ture时例外);

  • maximumPoolSize:线程池的最大线程数,等于核心线程与非核心线程的数量总和;

  • keepAliveTime:非核心线程最大空闲等待时间,在指定空闲时间后如果还没有任务则释放该线程;

  • workQueue:任务队列,当核心线程数用完时,任务被放入队列。

一、线程池是临时线程池

如果线程池是在当前线程创建的,且任务都是由当前线程提交的,线程池用完就消毁了,那么不管是哪种线程池,池中的线程都是由当前线程所创建,在这种场景下,InheritableThreadLocal能够将Context传给给线程池中的任一线程。

二、线程池是全局线程池

如果线程池是全局线程池:

  • 没有核心线程且非核心线程的keepAliveTime等于0:线程都是用到才创建,且由于keepAliveTime等于0,线程用完可能就释放了,在这种场景下,相当于是由当前线程创建子线程执行任务,因此能够实现透传;

  • 没有非核心线程:前(核心线程数)个任务的提交都会创建线程,也都是由当前线程创建,所以只有这几个任务的执行是能够正常获取父线程写入InheritableThreadLocal的数据的,后面提交的任务就不知道会被哪个核心线程拉取执行了;

到此,相信大家对“java中InheritableThreadLocal异步传递数据的实现原理”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: java中InheritableThreadLocal异步传递数据的实现原理

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • java中InheritableThreadLocal异步传递数据的实现原理
    本篇内容主要讲解“java中InheritableThreadLocal异步传递数据的实现原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java中Inher...
    99+
    2022-10-19
  • Linux中shell传递参数实现原理的示例分析
    这篇文章主要介绍了Linux中shell传递参数实现原理的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Shell 传递参数我们可以在执行 Shell 脚本时,向脚本...
    99+
    2023-06-09
  • 怎样实现Errai 2.0中的异步消息传递框架
    怎样实现Errai 2.0中的异步消息传递框架,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Errai是JBoss开发的一个基于GWT的框架,使用下一代WEB技术,用于构建富客...
    99+
    2023-06-17
  • 如何在Java和JavaScript中实现重定向的数据传递?
    重定向是一种常用的Web开发技术,它可以将用户请求重定向到另一个URL,并且可以在重定向过程中传递数据。在Java和JavaScript中实现重定向的数据传递有许多不同的方法,本文将为大家介绍其中的一些方法。 一、Java中实现重定向的数据...
    99+
    2023-06-26
    重定向 javascript 教程
  • 在Android中怎么实现与Activity的数据传递
    在Android中怎么实现与Activity的数据传递?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。使用Inten的putExtra传递第一个Activity中//创建意图对象...
    99+
    2023-05-31
    activity android roi
  • C++ Cartographer源码中关于传感器的数据传递实现
    目录激光雷达,超声雷达与点云数据处理与传递里程计与IMU数据的走向GPS与landmark数据走向总结上一节我们看了添加轨迹的相关处理,发现在此调用了LaunchSubscriber...
    99+
    2023-05-13
    C++ Cartographer数据传递 C++数据传递 C++ Cartographer
  • 如何实现angularjs2中父子组件的数据传递
    这篇文章主要介绍如何实现angularjs2中父子组件的数据传递,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!父到子组件之间的数据传递父组件模板中引用子组件 // ...
    99+
    2022-10-19
  • 大数据处理必备:Python异步编程实现原理与应用
    大数据处理是当前互联网时代的必要技能,Python是大数据处理的重要工具之一,而Python异步编程则是优化大数据处理效率的关键技术之一。本文将为你介绍Python异步编程的实现原理和应用,帮助你更好地掌握大数据处理技能。 一、Python...
    99+
    2023-08-04
    索引 异步编程 大数据
  • C++ Cartographer源码中关于传感器的数据传递如何实现
    今天小编给大家分享一下C++ Cartographer源码中关于传感器的数据传递如何实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我...
    99+
    2023-07-05
  • Android应用中怎么实现Activity之间的数据传递
    本篇文章为大家展示了Android应用中怎么实现Activity之间的数据传递,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。MainActivitypublic class MainActivity...
    99+
    2023-05-31
    android roi activity
  • Java 异步编程中,如何实现路径响应的异步处理?
    在现代的Web应用程序中,异步处理是非常重要的。这是因为在Web应用程序中,对于某些请求,可能需要进行较长时间的处理,例如处理大量数据或与其他服务进行通信。如果应用程序在这些请求上花费太长时间,将会给用户带来糟糕的体验。因此,异步处理可以...
    99+
    2023-10-31
    异步编程 响应 path
  • 如何在Java中实现高效的大数据异步编程?
    Java是一种广泛使用的编程语言,许多企业都使用它来处理大数据。在大数据处理中,异步编程是非常重要的。本文将介绍如何在Java中实现高效的大数据异步编程。 一、什么是异步编程? 在Java中,异步编程是指在程序执行期间,不必等待某些操作完成...
    99+
    2023-07-06
    大数据 异步编程 数据类型
  • 大数据处理中的异步编程:Java中的数据类型选择
    随着大数据时代的到来,大量数据的处理成为了一项重要的任务。同时,异步编程也成为了处理大数据的一个重要手段。在Java中,异步编程的实现方式有多种,其中数据类型的选择对于异步编程的实现也有很大的影响。本文将探讨Java中的数据类型选择在异步...
    99+
    2023-07-06
    大数据 异步编程 数据类型
  • java中hashmap的底层数据结构与实现原理
    目录Hash结构HashMap实现原理为何HashMap的数组长度一定是2的次幂?重写equals方法需同时重写hashCode方法总结Hash结构 HashMap根据名称可知,其实...
    99+
    2022-11-12
  • Java数据结构之图的原理与实现
    目录1 图的定义和相关概念2 图的存储结构2.1 邻接矩阵2.2 邻接表3 图的遍历3.1 深度优先遍历3.2 广度优先遍历4 图的实现4.1 无向图的邻接表实现4.2 有向图的邻接...
    99+
    2022-11-13
  • Java数据结构中图的原理与实现是怎样的
    小编今天带大家了解Java数据结构中图的原理与实现是怎样的,文中知识点介绍的非常详细。觉得有帮助的朋友可以跟着小编一起浏览文章的内容,希望能够帮助更多想解决这个问题的朋友找到问题的答案,下面跟着小编一起深入学习“Java数据结构中图的原理与...
    99+
    2023-06-29
  • JAVA-4NIO中如何实现Channel的数据传输
    JAVA-4NIO中如何实现Channel的数据传输?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直...
    99+
    2023-05-31
    channel java- java
  • 怎么在SpringCloud中使用Eureka实现服务之间的传递数据
    这期内容当中小编将会给大家带来有关怎么在SpringCloud中使用Eureka实现服务之间的传递数据,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、使用RestTemplate+Ip方式:1、传递数据...
    99+
    2023-06-15
  • 如何使用MongoDB实现数据的异步处理功能
    如何使用MongoDB实现数据的异步处理功能引言:在现代软件开发中,数据的异步处理已经成为了一个常见的需求。传统的数据库在面对大量数据处理的情况下,常常会出现性能瓶颈。而MongoDB作为一种NoSQL数据库,具有高性能、高可用性和可扩展性...
    99+
    2023-10-22
    MongoDB异步处理
  • Java中的数据类型是否支持大数据处理和异步编程?
    Java是一种广泛使用的编程语言,它在软件开发领域中占据着重要的地位。在处理大数据和异步编程方面,Java的数据类型和相关库是否能够胜任呢?本篇文章将从这两个方面展开讨论。 Java中的数据类型是否支持大数据处理? 在Java中,常见的数据...
    99+
    2023-07-06
    大数据 异步编程 数据类型
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作