首页 > 其他分享 >ThreadLocal最终版本

ThreadLocal最终版本

时间:2023-02-09 23:24:12浏览次数:54  
标签:变量 ThreadLocalMap 最终 用户 ThreadLocal 线程 版本 多线程

ThreadLocal工作原理

目录

一、官方文档描述

从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。

ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。

我们可以得知 ThreadLocal 的作用是:提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。

二、为什么使用ThreadLocal

我们的系统中同时会有很多用户请求,那每个请求都带有用户信息,我们知道通常都是一个线程处理一个用户请求,我们可以把用户信息丢到Threadlocal里面,让每个线程处理自己的用户信息,线程之间互不干扰。

我们程序在处理用户请求的时候,通常后端服务器是有一个线程池,来一个请求就交给一个线程来处理,那为了防止多线程并发处理请求的时候发生串数据,比如AB线程分别处理用户A和用户B的请求,A线程本来处理用户A的请求,结果访问到用户B的数据上了,造成了数据紊乱。

所以在A线程中要达到的效果是只能够操作A线程中的数据,而不应该去操作不属于本线程之内的数据,而ThreadLocal就可以达到这样的一种效果。

效果如下所示:

上述图中场景伪代码说明:

//存放用户信息的ThreadLocal
private static final ThreadLocal<UserInfo> userInfoThreadLocal = new ThreadLocal<>();

public Response handleRequest(UserInfo userInfo) {
    Response response = new Response();
    try {
        // 1.用户信息set到线程局部变量中
        userInfoThreadLocal.set(userInfo);
        doHandle();
    } finally {
        // 3.使用完移除掉
        userInfoThreadLocal.remove();
    }
    return response;
}

//每个线程执行的业务逻辑处理
private void doHandle () {
    // 2.实际用的时候取出来
    UserInfo userInfo = userInfoThreadLocal.get();
    // 查询用户资产
    queryUserAsset(userInfo);
}

2.1、案例

感受一下ThreadLocal 线程隔离的特点

不使用ThreadLocal

对应的结果如下所示:

从结果可以看出多个线程在访问同一个变量的时候出现的异常,线程间的数据没有隔离。


使用ThreadLocal

下面我们来看下采用 ThreadLocal 的方式来解决这个问题的例子。

将结果打印到控制台,查看输出信息,可以看到线程之间实现了隔离。

对应的输出结果:

三、ThreadLocal和syncronized关键字区别

虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题, 不过两者处理问题的角度和思路不同。

synchronized ThreadLocal
原理 同步机制采用’以时间换空间’的方式, 只提供了一份变量,让不同的线程排队访问 hreadLocal采用’以空间换时间’的方式, 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰
侧重点 多个线程之间访问资源的同步 多线程中让每个线程之间的数据相互隔离

虽然使用ThreadLocal和synchronized都能解决问题,但是使用ThreadLocal更为合适,因为这样可以使程序拥有更高的并发性。

因为synchronized关键字关注的是多线程对共享变量的操作;而ThreadLocal关注的是是共享变量副本的问题,我们希望的是在线程上下文中都可以使用到这个线程中的共享变量的副本,在不使用的时候将其移除掉即可,那么就可以使用ThreadLocal来进行解决。

四、数据结构

五、源码分析

set方法

对应的流程如下所示:

  • 1、首先获取当前线程,并根据当前线程获取一个ThreadLocalMap;

  • 2、如果获取的ThreadLocalMap不为空,则将参数设置到Map中(当前ThreadLocal的引用作为key) ;

  • 3、 如果ThreadLocalMap为空,则给该线程创建 ThreadLocalMap,并设置初始值;

get方法

具体分析下执行流程:

  • 1、首先获取当前线程, 根据当前线程获取得到ThreadLocalMap;
  • 2、如果获取的Map不为空,则在Map中以ThreadLocal的引用作为key来在Map中获取对应的Entry e,否则执行4步骤;
  • 3、如果e不为null,则返回e.value,否则执行4步骤;
  • 4、ThreadLocalMap为空或者e为空,则通过initialValue函数获取初始值value,然后用ThreadLocal的引用和value作为firstKey和firstValue创建一个新的ThreadLocalMap;

标签:变量,ThreadLocalMap,最终,用户,ThreadLocal,线程,版本,多线程
From: https://www.cnblogs.com/likeguang/p/17107452.html

相关文章

  • git 版本回退
    Git 的版本回退操作 内容介绍:一、时光穿梭机-版本回退二、查看版本,确定需要回到的时刻点三、回退指令:  时光穿梭机-版本回退当把git从仓库的指令用熟之后......
  • KubeSphere 3.3.2 版本正式发布!
    距离上一个版本v3.3.1发布,已经过了3个多月,今天我们很高兴宣布KubeSpherev3.3.2正式发布!此版本由68位贡献者参与代码提交,感谢各位贡献者对KubeSphere项目的支持与......
  • n包管理Node版本
      刚刚在VueCLI官网看到了一个有趣的东西,在此做一下记录:描述:https://cli.vuejs.org/zh/guide/installation.html说明:  n在macOS、Linux上受支持,n不适用于M......
  • KubeSphere 3.3.2 版本正式发布!
    距离上一个版本v3.3.1发布,已经过了3个多月,今天我们很高兴宣布KubeSpherev3.3.2正式发布!此版本由68位贡献者参与代码提交,感谢各位贡献者对KubeSphere项目的支持......
  • EasyCVR新版本如何通过接口获取AI智能分析网关推送的告警照片?
    在AI人工智能技术进一步落地应用的趋势下,基于云边端深度融合与协同的“AI+”模式,已经成为当前行业与技术发展的新趋势。基于EasyCVR和智能分析网关的AI智能识别与分析能力,通......
  • php版本的umd电子书制作工具
    代码:<?phpset_time_limit(0);ini_set('memory_limit','-1');//error_reporting(E_ALL);//ini_set('display_errors',0);/**+--------------------------------......
  • spring-security-oauth2-client与jdk版本不符合报错
    报错描述:java.lang.UnsupportedClassVersionError:org/springframework/security/oauth2/client/registration/ClientRegistrationRepositoryhasbeencompiledbyamo......
  • OpenSSH 9.2P1升级以及版本显示的处理过程
    说明本次维护的时间是2023-2-9最新已发布的补丁是OpenSSH9.2P1版本其他本本应该是类似处理.下载介质在OpenSSH官网打开相关界面.http://www.openssh.com/......
  • git取消版本控制
    参考:https://blog.csdn.net/lzx5290/article/details/127665687?spm=1001.2014.3001.5506执行命令如下:MicrosoftWindows[版本10.0.19041.208](c)2020MicrosoftCo......
  • 【AGC】已上架的应用签名发生变化升级新版本问题
    ​关于AGC的已上架的应用签名发生变化,该如何升级新版本问题。问题背景:cp反馈目前已有一个应用程序上传至华为市场。由于更新了开发供应商,导致新版安装包的签名发生了变化......