当前位置:首页 > 科技  > 软件

深度解析Java Thread Locals工作原理

来源: 责编: 时间:2024-05-29 08:59:47 78观看
导读一、前言在Java中,线程本地变量的作用域是整个线程。这意味着这种变量可以从线程中的任何位置设置,并可以从同一线程的任何位置访问。从一个线程设置的值对另一个线程是不可访问的。我们应该知道,Java中有两种类型的线程

一、前言

在Java中,线程本地变量的作用域是整个线程。这意味着这种变量可以从线程中的任何位置设置,并可以从同一线程的任何位置访问。从一个线程设置的值对另一个线程是不可访问的。8h928资讯网——每日最新资讯28at.com

我们应该知道,Java中有两种类型的线程本地类——ThreadLocal和InheritableThreadLocal。让我们看看这两者之间的区别。8h928资讯网——每日最新资讯28at.com

二、ThreadLocal类

下面是一个如何声明线程本地变量的示例。变量user是一个ThreadLocal变量,它保存一个User类型的变量(类或接口)。请注意,这里变量被声明为public和static,以便user变量可以从代码中的任何位置访问。8h928资讯网——每日最新资讯28at.com

// 声明一个线程本地变量userpublic static final ThreadLocal user                      = new ThreadLocal<>();

下面是我们如何为一个线程设置和获取user。该示例显示user变量被设置为用户对象bob。在同一线程中,如果我们调用get()方法,就会检索到用户bob。8h928资讯网——每日最新资讯28at.com

// 设置调用线程的user值user.set(new User("bob"));// 获取调用线程的user值User requestUser = user.get();

请注意,即使user变量对整个代码库是可访问的,但set(..)方法确保传递给它的用户对象与calling线程相关联。get()方法也会检索与calling线程相关联的用户对象,这就是为什么当在不同线程上调用get()方法时,它不会检索到bob而是其他用户(或null)的原因。每个Java线程都与一个包含该线程所有设置的线程本地变量的ThreadLocal映射相关联。8h928资讯网——每日最新资讯28at.com

如果我们在未设置任何值的情况下调用get()方法,该方法将简单地返回null。8h928资讯网——每日最新资讯28at.com

然而,你可以创建一个带有Lambda Supplier的线程本地对象,它将返回一个初始的用户对象。下面的示例显示了一个Supplier,它返回一个名为anonymous的用户。因此,如果在未设置值的情况下调用ThreadLocal上的get()方法,则会调用Supplier上的get()方法,并将该值设置为用户的初始值。8h928资讯网——每日最新资讯28at.com

// 声明一个带有Supplier的线程本地变量userpublic static ThreadLocal user           = ThreadLocal.withInitial(                () -> new User("anonymous"))// 返回AnonymousUser requestUser = user.get();

你也可以通过简单地调用remove()方法来删除之前设置的值,如下所示。8h928资讯网——每日最新资讯28at.com

// 删除调用线程的user值user.remove();

该方法基本上会删除与线程相关联的用户对象。更重要的是,其他线程不会受到此操作的影响。8h928资讯网——每日最新资讯28at.com

如果我们以图表形式来可视化线程本地变量,它看起来会像这样。请注意,两个线程的user变量指向的是不同的用户对象。8h928资讯网——每日最新资讯28at.com

图片图片8h928资讯网——每日最新资讯28at.com

三、ThreadLocal和子线程

到目前为止,我们的讨论主要集中在单个Java线程上。如果一个Java线程启动了一个新的子线程,子线程会自动能够访问父线程中定义的线程本地变量吗?8h928资讯网——每日最新资讯28at.com

答案是否定的!子线程无法访问父线程的线程本地变量,这是有充分理由的。如果能够访问,那么存储在线程本地变量中的对象就必须为线程安全而编写,因为多个线程能够访问同一个用户对象。这是Java工程师做出的一个很好的默认设计决策。8h928资讯网——每日最新资讯28at.com

但是,在某些情况下,这种访问是有用的。想象一个Web应用程序的场景,许多用户正在访问应用程序。一个单独的Java线程与整个请求处理过程中的用户相关联,你可以想象用户对象存储在线程的线程本地对象中(这是许多应用服务器和框架如Spring Boot所做的)。但是,你可能希望生成的子线程也能访问这些用户信息。8h928资讯网——每日最新资讯28at.com

对于这种场景,Java提供了另一个名为InheritableThreadLocal的类。8h928资讯网——每日最新资讯28at.com

四、InheritableThreadLocal类

使用这个类的语法与ThreadLocal类基本相同。下面的示例显示了InheritableThreadLocal类的相应方法。8h928资讯网——每日最新资讯28at.com

// 声明一个可继承的线程本地变量userpublic static final InheritableThreadLocal user            = new InheritableThreadLocal<>();// 设置调用线程的user值user.set(new User("bob"));// 获取调用线程的user值User requestUser = user.get();// 删除调用线程的user值user.remove();

与Thread Local映射一样,每个线程也有一个用于可继承线程本地变量的映射。这里的关键区别是,当创建子线程时,子线程的可继承线程本地映射会从父线程克隆。因此,可继承线程本地变量对子线程也是可访问的。8h928资讯网——每日最新资讯28at.com

如果我们以图表形式可视化可继承线程本地变量,它看起来会像这样。可以看到,InheritableThreadLocal映射是从父线程克隆而来的。8h928资讯网——每日最新资讯28at.com

图片图片8h928资讯网——每日最新资讯28at.com

五、注意事项

正如上图所清楚显示的,可继承线程本地变量所见到的优势也是一种缺点。默认情况下,当创建子线程时,可继承线程本地映射也会被克隆。但是你也可以看到,user指向父线程和子线程中相同的用户对象。8h928资讯网——每日最新资讯28at.com

这意味着用户对象可以从多个线程访问,因此需要以线程安全的方式编写。换句话说,如果使用InheritableThreadLocal类,之前ThreadLocal类的线程安全性就会丢失。这对于你的设计可能是完全有效的。8h928资讯网——每日最新资讯28at.com

然而,还有一种更安全的方法。我们可以在创建InheritableThreadLocal时指定一个childValue(..)方法。事实上,在下面的示例中,我们同时指定了一个初始值和一个子值。8h928资讯网——每日最新资讯28at.com

public static final InheritableThreadLocal user                    = new InheritableThreadLocal<>() {   @Override   protected User initialValue() {       return new User("anonymous");    }   @Override   protected User childValue(User parentValue) {       return new User(parentValue.getId());    }};

在这种更改下,当Inheritable Thread Local映射被克隆时,与子线程关联的值将使用childValue(..)方法设置,该方法通过传递父线程的值来初始化每个Inheritable Thread Local。由于我们是从childValue(..)方法创建了一个新的对象,因此用户对象不会在父线程和子线程之间共享。通过这一改变,我们恢复了线程安全性,同时也能以只读的方式访问用户对象(通过有效地创建一个副本)。8h928资讯网——每日最新资讯28at.com

同样,如果我们以图表形式可视化Inheritable Thread Locals,它看起来会像这样。很明显,现在用户分别指向父线程和子线程中的不同用户对象。8h928资讯网——每日最新资讯28at.com

图片图片8h928资讯网——每日最新资讯28at.com

希望这能让你对Java Thread Local变量有一个较好的理解,以及它们在应用程序中如何使用。8h928资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-91379-0.html深度解析Java Thread Locals工作原理

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Git 不要只会 Pull 和 Push,这五条提高效率的命令得掌握!

下一篇: 畅爽领先游戏体验 玩手游就选三星 S24 Ultra

标签:
  • 热门焦点
  • JavaScript学习 -AES加密算法

    JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • .NET 程序的 GDI 句柄泄露的再反思

    .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • 使用AIGC工具提升安全工作效率

    使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 梁柱接棒两年,腾讯音乐闯出新路子

    梁柱接棒两年,腾讯音乐闯出新路子

    文丨田静 出品丨牛刀财经(niudaocaijing)7月5日,企鹅FM发布官方公告称由于业务调整,将于9月6日正式停止运营,这意味着腾讯音乐长音频业务走向消亡。腾讯在长音频领域还在摸索。为
  • 携众多高端产品亮相ChinaJoy,小米带来一场科技与人文的视听盛宴

    携众多高端产品亮相ChinaJoy,小米带来一场科技与人文的视听盛宴

    7月28日,全球数字娱乐领域最具知名度与影响力的年度盛会中国国际数码互动娱乐展览会(简称ChinaJoy)在上海新国际博览中心盛大开幕。作为全球领先的科
  • 消息称小米汽车开始筛选交付中心:需至少120个车位

    消息称小米汽车开始筛选交付中心:需至少120个车位

    IT之家 7 月 7 日消息,日前,有微博简介为“汽车行业从业者、长三角一体化拥护者”的微博用户 @长三角行健者 发文表示,据经销商集团反馈,小米汽车目前
  • 三星电子Q2营收60万亿韩元 存储业务营收同比仍下滑超过50%

    三星电子Q2营收60万亿韩元 存储业务营收同比仍下滑超过50%

    7月27日消息,据外媒报道,从三星电子所发布的财报来看,他们主要利润来源的存储芯片业务在今年二季度仍不乐观,营收同比仍在大幅下滑,所在的设备解决方案
  • 三星显示已开始为AR设备研发硅基LED微显示屏

    三星显示已开始为AR设备研发硅基LED微显示屏

    7月18日消息,据外媒报道,随着苹果首款头显产品Vision Pro在6月份正式推出,AR/VR/MR等头显产品也就将成为各大公司下一个重要的竞争领域,对显示屏这一关
Top