【Java】ThreadLocal原理与使用场景

ThreadLocal原理:

字段:

//ThreadLocal对象的哈希码
private final int threadLocalHashCode = nextHashCode();


//生成ThreadLocal对象的哈希码时,需要用到该对象,从0开始
private static AtomicInteger nextHashCode =
        new AtomicInteger();


//哈希码的增长值
private static final int HASH_INCREMENT = 0x61c88647;


        nextHashCode()方法:


private static int nextHashCode() {
        //通过AtomicInteger对象生成ThreadLocal对象的哈希码并返回
        //步长为:HASH_INCREMENT
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

方法实现:

        (1)get()方法:

public T get() {
        //获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的ThreadLocalMap对象
        ThreadLocalMap map = getMap(t);
        //判断ThreadLocalMap对象是否为空
        //map不为null说明有键值对
        if (map != null) {
            //在map中,ThreadLocal作为key
            ThreadLocalMap.Entry e = map.getEntry(this);
            //如果key不为空
            if (e != null) {
                @SuppressWarnings("unchecked")
                //通过key获取值并返回
                T result = (T)e.value;
                return result;
            }
        }
        //如果map为null,则创建map
        //当前ThreadLocal对象作为key,null作为value存入map中
        //返回null
        return setInitialValue();
    }

        (2)set()方法:

public void set(T value) {
        //获取当前线程的ThreadLocalMap对象
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        
        //如果map不为null
        if (map != null)
            //将当前ThreadLocal作为key
            //参数value作为值,存入ThreadLocalMap中
            map.set(this, value);
        else
            //map为null,则创建map
            //将当前ThreadLocal对象作为firstKey,参数value作为firstValue
            createMap(t, value);
    }

通过set方法,我们可以知道:

        1、线程调用ThreadLocal对象的set方法时,会获取当前线程的ThreadLocalMap对象。

        2、随后会将当前ThreadLocal对象作为key,参数value作为值存储到线程内部的ThreadLocalMap对象中。

        3、这意味着即使ThreadLocal是多个线程共享的变量也不会存在线程安全问题,因为每个线程都只在操作自己的ThreadLocalMap,ThreadLocal只是作为key保存在map中。

        (3)remove()方法:

public void remove() {
         //获取当前线程的ThreadLocalMap对象
         ThreadLocalMap m = getMap(Thread.currentThread());
         //如果map不为null
         if (m != null)
             //将当前ThreadLocal对象从ThreadLocalMap中移除
             m.remove(this);
     }

ThreadLocalMap、ThreadLocal、Thread三者之间的联系:

测试:

        (1)User类:

package test;

public class User {

    private Integer id;

    private String name;


    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }


    public User(){

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

        (2)UserHolder类:

package test;

public class UserHolder {


    private static final ThreadLocal<User> threadLocal = new ThreadLocal<>();

    public static void set(User user){
        threadLocal.set(user);
    }


    public static User get(){
        User user = threadLocal.get();
        return user;
    }
}

       ThreadLocal作为静态字段存在于UserHolder类中,UserHolder的set方法、get方法实际上都是由ThreadLocal实现,这里使用到了组合的思想。

        (3)ThreadLocalTest类:

package test;

public class ThreadLocalTest {


    public static void main(String[] args) throws InterruptedException {

        new Thread(() -> {
            System.out.println("Thread-1线程运行,存储User对象到TheadLocal中...");
            createAndHold(1,"张三");
            User user = UserHolder.get();
            System.out.println(user);
        }, "Thread-1").start();
        
        System.out.println("main线程阻塞...");
        Thread.sleep(3000);
        System.out.println("main线程运行,获取UserHolder存储的User对象...");
        User user = UserHolder.get();
        System.out.println("user对象:" + user);
    }

    private static void createAndHold(Integer id,String name){
        User user = new User(id, name);
        UserHolder.set(user);
    }
}

代码解读:

        1、main线程一开始会阻塞3s,Thread-1线程运行,将User对象存入ThreadLocal并打印。

        2、main线程解除阻塞后,会去获取ThreadLocal中存储的User对象;照理来说,ThreadLocal对象是静态成员,对于两个线程来说是共享变量,此时main线程应该会获取到Thread-1存入的User对象。

        3、但我们知道,ThreadLocal真正操作的是每个线程内部的ThreadLocalMap,ThreadLocal对象只作为key存储到每个线程自己的ThreadLocalMap中,我们可以通过key找到value,实现线程间的隔离。

测试结果:

ThreadLocal使用场景:

        (1)多线程隔离 多个线程使用ThreadLocal访问共享变量,每个线程都会得到共享变量的一个副本,后续多个线程自己所属副本的所有操作不会冲突,没有线程安全问题。

        (2)线程内共享ThreadLocal 可以用于在整个线程生命周期内共享这些上下文信息,而不需要显式地传递参数。

        (3)存储用户信息在Web应用中,可能会在用户登录后将用户身份信息存储在 ThreadLocal 中,以便在整个请求处理过程中方便地访问用户信息,而不必在每个方法中都传递用户信息参数。

       

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/283493.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用docker build构建image

文章目录 环境步骤准备例1&#xff1a;基本用法例2&#xff1a;缓存layer例3&#xff1a;Multi-stage例4&#xff1a;Mountcache mountbind mount 例5&#xff1a;参数例6&#xff1a;Export文件例7&#xff1a;测试 参考 环境 RHEL 9.3Docker Community 24.0.7 步骤 在Dock…

Pix2Pix如何工作?

一、说明 在本指南中&#xff0c;我们将重点介绍 Pix2Pix [1]&#xff0c;它是用于配对图像翻译的著名且成功的深度学习模型之一。在地理空间科学中&#xff0c;这种方法可以帮助传统上不可能的广泛应用&#xff0c;在这些应用中&#xff0c;我们可能希望从一个图像域转到另一个…

认识Linux基本指令之 “touch mkdir rm”

01.touch指令 语法:touch [选项]... 文件... 功能&#xff1a;touch命令参数可更改文档或目录的日期时间&#xff0c;包括存取时间和更改时间&#xff0c;或者新建一个不存在的文件 常用选项&#xff1a; -a 或--timeatime或--timeaccess或--timeuse只更改存取时间。 -c…

JAVA:利用JUnit进行高效的单元测试

1、简述 在软件开发中&#xff0c;单元测试是确保代码质量和可维护性的关键步骤。JUnit作为Java领域最流行的单元测试框架之一&#xff0c;提供了简单而强大的测试工具&#xff0c;可以帮助开发者在项目开发过程中及时发现和修复代码中的问题。本文将介绍JUnit的基本用法以及一…

3D视觉-3D测量技术对比

从前面四种主流的 3D 测量技术来看&#xff0c;其优点和缺点都很明显&#xff0c;没有单独一种技术可以适用于所有的三维测量场景&#xff0c;从实际应用来看&#xff0c;双目与结构光在人脸识别&#xff0c;拆码垛定位&#xff0c;静态尺寸测量等应用上最为广泛。激光三角法因…

【CISSP学习笔记】6. 安全开发

该知识领域涉及如下考点&#xff0c;具体内容分布于如下各个子章节&#xff1a; 理解安全并将其融入软件开发生命周期 (SDLC) 中在软件开发环境中识别和应用安全控制评估软件安全的有效性评估获得软件对安全的影响定义并应用安全编码准则和标准 6.1. 系统开发控制 6.1.1. 软…

数据转换的三剑客:Pandas 中 apply、map 和 applymap 方法的应用指南

数据转换的三剑客&#xff1a;Pandas 中 apply、map 和 applymap 方法的应用指南 ​ 在 Pandas 中&#xff0c;apply、map 和 applymap 是常用的数据转换和处理方法&#xff0c;它们为数据分析和数据处理提供了灵活的功能。这些方法可以根据具体的需求选择合适的方法进行操作。…

如何使用ModuleShifting测试Module Stomping和Module Overloading注入技术

关于ModuleShifting ModuleShifting是一款针对Module Stomping和Module Overloading注入技术的安全测试工具&#xff0c;该工具基于Python ctypes实现其功能&#xff0c;因此可以通过Python解释器或Pyramid在内存中完整执行&#xff0c;这样就可以避免使用编译加载器了。 需要…

普中STM32-PZ6806L开发板(HAL库函数实现-按键扫描)

简介 实现按键扫描, 实现四个按键按下控制灯的亮灭 电路原理图 按键电路原理图 按键与主芯片引脚原理图 其他知识 原理图分析 Key_UP按下会有高电平输入, 所以电路设置应该是默认低电平, 初始化为下拉输入 Key_Left/Right/Down按下会有低电平&#xff0c; 初始化为下拉输…

鸿蒙开发 - 认证账号

注册成功后&#xff0c;进行账号认证 认证成功后就可以进行开发了

2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项样题卷②

2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项&#xff08;高职组&#xff09; 样题&#xff08;第2套&#xff09; 目录 2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项&#xff08;高职组&#xff09; 样题&#xff08;第2套&#xff09; 模块…

【pandas_不重复项计数】

听说WPS没有非重复项计数的功能&#xff0c;而office需要添加到数据模型之后&#xff0c;才可以使用该功能。而用pandas&#xff0c;既可以对重复项计数&#xff0c;又可以对非重复项计数。 # 使用提醒: # 1. xbot包提供软件自动化、数据表格、Excel、日志、AI等功能 # 2. pack…

【C++】手撕 Vector类

目录 1&#xff0c;vector类框架 2&#xff0c;vector () 3&#xff0c;pinrt() 4&#xff0c;vector(int n, const T& value T()) 5&#xff0c;vector(const vector& v) 6&#xff0c;vector(InputIterator first, InputIterator last) 7&#xff0c;~vector…

20231228在Firefly的AIO-3399J开发板的Android11的Firefly的AIO-3399J开发板的DTS配置单前置摄像头ov13850

20231228在Firefly的AIO-3399J开发板的Android11的Firefly的AIO-3399J开发板的DTS配置单前置摄像头ov13850 2023/12/28 12:30 开发板&#xff1a;Firefly的AIO-3399J【RK3399】 SDK&#xff1a;rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBr…

uni-app 前后端调用实例 基于Springboot

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

怎么解决 Nginx反向代理加载速度慢?

Nginx反向代理加载速度慢可能由多种原因引起&#xff0c;以下是一些可能的解决方法&#xff1a; 1&#xff0c;网络延迟&#xff1a; 检查目标服务器的网络状况&#xff0c;确保其网络连接正常。如果目标服务器位于不同的地理位置&#xff0c;可能会有较大的网络延迟。考虑使用…

win10系统请将eNSP相关应用程序添加到windows firewall的允许程序列表,并允许其在公用网络上运行!的解决办法

很多学习网络的小伙伴&#xff0c;在下载安装eNSP后&#xff0c;打开程序跳出&#xff1a;请将eNSP相关应用程序添加到windows firewall的允许程序列表&#xff0c;并允许其在公用网络上运行! 是不是挺闹心的! 其实&#xff0c;原因是很简单&#xff0c;就是win10系统防火墙访…

本地git服务器的使用

Windows上使用&#xff1a; 首先要在windows开发机上生成密钥&#xff1a; 1.安装git&#xff0c;首先去git官网下载git&#xff0c;https://git-scm.com/downloads&#xff0c;下载.exe格式并安装。 2.从程序目录启动“Git Bash” 3.键入命令&#xff1a;ssh-keygen -t rsa -…

快速上手:探索Spring MVC的学习秘籍!

SpringMVC概述 1&#xff0c;SpringMVC入门案例1.2 案例制作步骤1:创建Maven项目步骤2:补全目录结构步骤3:导入jar包步骤4:创建配置类步骤5:创建Controller类步骤6:使用配置类替换web.xml步骤7:配置Tomcat环境步骤8:启动运行项目步骤9:浏览器访问步骤10:修改Controller返回值解…

YOLOv8主干改进 更换柱状神经网络RevCol

一、Reversible Column Networks论文 论文地址:2212.11696.pdf (arxiv.org) 二、Reversible Column Networks结构 Reversible Column Networks 是一种用于量子计算的新型结构。它由一系列可逆操作组成,可以在量子计算中进行高效的信息传递和处理,具有可扩展性、灵活性、…