Java常用类:ThreadLocal

Java:关于 ThreadLocal 的知识来了! 面试题: 1、ThreadLocal 与 ThreadLocalMap 的数据结构和关系? 2、ThreadLocal 的 key 是弱引用,这是为什么? 3、ThreadLocal 内存泄漏问题你知道吗? 4、ThreadLocal 中最后为什么要加 remove 方法? 一、ThreadLocal 简介 1、ThreadLocal 是什么? ThreadLocal 能提供线程局部变量,这些变量与正常的变量不同,因为每一个线程在访问 ThreadLocal 实例的时候(通过 get 或 set 方法)都有 阅读详情

作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)

ThreadLocal

ThreadLocal类主要是为了解决多线程并发,出现线程共用变量的问题。与synchronized等同步方法不同的是,synchronized是采取线程排队的方式,使得同一时间点只有一个线程访问非线程安全的变量;而ThreadLocal是为每个线程创建非线程安全变量的副本,线程之间无法交叉访问变量,从而解决并发问题。
ThreadLocal支持泛型变量,在类中初始化如下:

private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>()

1.几个重要的方法

//初始化方法,默认返回null
protected T initialValue() {
        return null;
    }
//set方法,给本地变量赋值,其实是用的ThreadLocalMap内部类来保存的
//将当前的线程对象作为key,传进来的value作为值
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
//获取本地变量
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        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;
    }
//移除当前的本地变量
public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

主要就是以上四个方法,ThreadLocal通过ThreadLocalMap内部类,达到为每个线程创建一个变量的副本,使得每个线程之间互不干扰的访问非线程安全的变量。简单的理解就是ThreadLocal通过map以线程对象为key,变量值为value,线程只能修改获取它自己线程对应的变量。

2.简单例子

public class ThreadLocalDemo {
	//重写initialValue方法
    private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };
	//获取的时候将值递增1
    public  Integer getValue(){
        threadLocal.set(threadLocal.get()+1);
        return threadLocal.get();
    }

    public static void main(String[] args) {
        ThreadDemo thread1 = new ThreadDemo(new ThreadLocalDemo());
        ThreadDemo thread2 = new ThreadDemo(new ThreadLocalDemo());
        ThreadDemo thread3 = new ThreadDemo(new ThreadLocalDemo());
        thread1.run();
        thread2.run();
        thread3.run();
    }

}

class ThreadDemo extends Thread{
    private ThreadLocalDemo threadLocalDemo;
    public ThreadDemo(ThreadLocalDemo threadLocalDemo){
        this.threadLocalDemo = threadLocalDemo;
    }

    @Override
    public void run() {
        for(int i=0;i<3;i++){
            System.out.println(this.getName()+":"+this.threadLocalDemo.getValue());
        }
    }
}

结果:可以看出线程之间没有出现干扰的情况,变量都是从1递增到3,如果不使用ThreadLocal,那么三个线程同时访问一个变量就会出现并发的问题。

Thread-0:1
Thread-0:2
Thread-0:3
Thread-1:1
Thread-1:2
Thread-1:3
Thread-2:1
Thread-2:2
Thread-2:3

3.实际案例

在工作中也接触到了ThreadLocal,使用场景有在一次请求中保存用户信息;或者需要将日志记录到数据库中,每个请求的日志信息都不一样。

将用户信息保存到ThreadLocal中

在一次http请求中,会经过mvc三层,在这个过程中可能会在多个方法中需要获取用户信息,如果每次都读取数据库,会造成不必要的资源浪费。使用ThreadLocal能够达到一次读取,多次使用的效果。

//在请求中,验证用户信息无误后将用户信息存在ThreadLocal中,在这次请求
//直到返回结果的过程中,都可以通过getLoginUser()获取用户的信息。
public abstract class AbstractBaseController {

    private static final ThreadLocal<LoginUserEntity> loginUserContainer = new ThreadLocal<>();

    /**
     * 初始化request和response对象
     */
    @ModelAttribute
    private final void initRequestAndResponse() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (Objects.nonNull(authentication)) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof LoginUserEntity) {
                loginUserContainer.set((LoginUserEntity)principal);
            }

        }
    }

    /**
     * 获取当前线程的登录用户user对象
     *
     * @return LoginUserEntity
     */
    protected final LoginUserEntity getLoginUser() {
        return loginUserContainer.get();
    }

}

总结:ThreadLocal相比其他多线程解决方案来说,比较适合于变量隔离的场景,如果是要对一个值进行累加或累减再存回数据库,如秒杀的库存等,就不太适合使用ThreadLocal,那种业务场景还是适合使用同步来解决。

Qt+OpenGL+Cesium三件套:打造高性能3D GIS界面的5个关键技巧 本文深入探讨了如何利用Qt、OpenGL与Cesium三件套打造高性能3D GIS界面的5个核心技巧。内容涵盖多线程渲染架构设计、OpenGL状态管理与批处理优化、内存与显存高效管理、Qt UI与3D场景深度集成,以及跨平台部署与性能调优实战,旨在帮助开发者解决海量3D Tiles数据渲染的性能瓶颈,实现流畅的交互体验。 阅读详情

相关推荐

OBS技术深度剖析:从开源直播工具到专业制作引擎的进化之路

本文深入剖析了开源直播软件OBS的技术架构与发展历程。从2012年诞生至今,OBS已成长为直播领域的事实标准,其成功源于模块化设计和开源协作模式。文章详细解析了OBS的核心技术:1) 分层架构与插件系统,2) GPU加速的渲染管线,3) 智能音频处理,4) 多平台编码优化。同时探讨了虚拟摄像头、浏览器源等高级功能的实现原理,并提供了性能优化方案和硬件配置建议。随着AI、WebRTC等新技术发展,OBS将持续引领实时内容创作工具的创新,为开发者和创作者提供更强大的技术支持。

程序猿老樊的博客 324

使用ThreadLocal却出现了有并发问题?

最近同事发现所做的app在未登陆的情况刷feed的时候,相同参数请求,返回的结果确不稳定。于是找到我帮忙排查问题。 听到问题第一反应应该是并发场景下数据安全的问题,于是clone了他们的项目,对着代码开始排查。 使用的是springmvc,每个Controller(单例)都继承于一个BaseController,BaseController实现了IWebContext接口,注入了reque

weixiaomao0801的博客 3088

CAN开发笔记(TI开发者推荐笔记)

查阅了很多资料没有查阅到关于5728芯片CAN模块寄存器的介绍,希望通过本文能给做CAN驱动的后来者有一点参考意义,我也是刚接触CAN模块有些不足请各位多多指正。 由下图所示是CAN模块初始化流程图 首先要开始初始化,设置CAN位时间,然后配置message objects, 完成初始化。 1.开始初始化 首先要控制DCAN_CTL 寄存器,该寄存器是CAN模块的总控制器,很多配置通过...

weixin_44316996的博客 3561

利用threadLocal 把拦截器中的对象传递到controller或service中

可以用 request 携带数据。更优雅的方式是用threadlocal。请求进入tomcat 和产生响应前,都处于同一个线程中比如在一个登录拦截器中,在preHandle方法中登录成功后,放行前,想把user对象传到controller或service中 创建一个类UserThreadLocal.class public class UserThreadLocal { //把构造函数私有,外

写笔记的地方 1万+

【七】Hadoop3.3.4基于ubuntu24的分布式集群安装

本次安装实验基于苹果m2芯片的mac系统,使用vmware fusion搭建三台ubuntu24分布式虚拟机,确保在三台机器上安装了Java jdk8,并配置了免密码登录,网络互通,防火墙关闭,授时服务器已经同步。访问apche官网源,下载3.3.4版本,我们用二进制通用版即可,因为hadoop运行在java环境,跨平台性使得无需编译arm架构版本。至此,Hadoop的安装完成,包括hdfs文件存储系统,mapreduce计算框架,yarn资源管理系统均能正常、稳定使用。

qq_31412425的博客 2158

13、Java 中 MQTT 异步通知与回调的使用及传感器命令处理

本文详细介绍了在 Java 中使用 MQTT 的异步通知与回调机制,并展示了如何通过 Paho Java 客户端处理与传感器交互的命令。文章包含代码示例,讲解了 MQTT 客户端的连接、订阅、消息处理以及模拟传感器数据发布的过程,适用于希望在 Java 应用中实现 MQTT 通信与设备控制的开发者。

eee77的博客 159

ThreadLocal存储用户登录信息

一般来说如果我们需要获取当前用户信息的话,大家想到的都是在用户的登录的时候将用户的信息存到缓存中,然后登录不是会生成token吗,到时候如果哪个controller中需要用到用户信息的话,那我就将token传过去,然后再校验一下token,ckeckToken的逻辑中会给我返回我存在缓存中的用户信息,就比如用户id吧(直接存密码就有点不安全了),再通过id去查询数据库获得用户的用户名密码之类的。

weixin_46000937的博客 4862

【SECS】初识SECS协议

项目标题的第一位和第二位告诉下面有多少字节表示项目的长度。而项目的长度是指项目标题后面的字节数,这里第一个字节就是项目标题。1个字节可以表示的最大长度是0-255,所以只要项目标题后面的字节数小于等于254,都是0x01。

weixin_48618536的博客 1639

对ThreadLocal的使用以及内存泄漏问题的个人见解

1. ThreadLocal弱引用的设计不是产生内存泄漏的原因,而是为了解决内存泄漏 2. 进一步解决内存泄漏可以在使用完后,调用ThreadLocal.remove()是最好的方法。

金牌程序员东岂 533

【CANoe】CAPL_ECU上电后首帧报文发出时间检测

【CANoe】CAPL_ECU上电后首帧报文发出时间检测,通过CANoe I/O口检测电压实现

星Yeah 的博客 2507

图文:银行核心账务处理逻辑(白话篇)

银行账务系统分为对内账(记录银行自身资产负债)和对外账(处理客户交易),通过特定编码规则的账号体系进行管理。采用T型账户结构和凭证制度确保每笔交易可追溯,通过明细核算与综合核算双线并行、每日轧账核对(科目日结单、总账、日计表)实现账务精准平衡。从业务触发到最终账平的全流程体现了银行账务"分层记录、双向核对、闭环校验"的核心原则,保障资金流动的透明性与安全性。

银行信息系统应用架构详解 537

拦截器配置,获取请求头中的用户id,放置到ThreadLocal线程空间中

@Component public class AppTokenInterceptor extends HandlerInterceptorAdapter { /** * 前置拦截 - 获取请求头中的 userId , 放入到当前线程中 * * @param request * @param response * @param handler * @return * @throws Exception */

helpluozhao123的博客 2332

RISC-V CPU设计(三)---多周期CPU的设计与实现

基本情况 本多周期CPU支持RV32I指令集(fence,ecall,ebreak除外),已通过部分指令的测试,如代码有bug,欢迎指出。 模块划分 代码将CPU划分为以下几个模块: 1.控制单元:ControlUnit 用于产生控制信号,是CPU的大脑,指挥中枢。 2.分支决策单元:BranchUnit 用于决定B型指令是否发生跳转 3.立即数单元:ImmUnit 用于从指令中解析出立即数. 4.寄存器堆:RegisterFile RISC-V的32个寄存器,其中x0寄存器恒为0,不可更改。 5.指令存储

qq_40268672的博客 5540

Java基础【四】 - 常用类库:java.lang.ThreadLocal

使用场景 ThreadLocal和synchronized都是为了解决多线程中相同变量的访问冲突问题。synchronized保证同一时刻只有一个线程对共享变量进行操作,synchronized是时间换空间的体现。ThreadLocal使变量在每个线程中都有独立拷贝的共享变量,不会出现一个线程读取变量时而被另一个线程修改的现象。Threa...

weixin_34247032的博客 118

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java常用类库之ThreadLocal类

Java常用类库之ThreadLocal类 在项目开发过程之中,ThreadLocal是一个最为重要的引用数据类型的传递操作类,利用这个类可以非常轻松的实现数据的传输,同时也可以保证多个线程下的数据传输的正确性,由于ThreadLocal对于很多的初学者来说很难理解,所以下面就针对与当前给出的操作进行一些递进分析。 范例: 观察传统的引用传递 class Message{//信息的操作类 private String content;//类中的属性 public String getCon

liuzhenNSY的博客 285

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

掌握Java中的ThreadLocal

key不设置成弱引用的话就会造成和entry中value一样内存泄漏的场景。弱引用会在每次GC时回收,无论内存是否足够。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。一旦 key 被回收,ThreadLocalMap 在进行 set、get 的时候就会对 key 为 null 的 Entry 进行清理。

mazouri的博客 1779

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【Java】ThreadLocal详解

ThreadLocal 详解

啊松同学的博客 1450

Java:ThreadLocal解析

ThreadLocal 是java中非常重要的内容,本文尽可能的全面介绍了 ThreadLocal内容,包括内存泄漏,key弱引用等问题第一种解释:ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

qq_46119575的博客 2041

java中ThreadLocal的使用

文章目录在Map中存储用户数据在ThreadLocal中存储用户数据 java中ThreadLocal的使用 ThreadLocal主要用来为当前线程存储数据,这个数据只有当前线程可以访问。 在定义ThreadLocal的时候,我们可以同时定义存储在ThreadLocal中的特定类型的对象。 ThreadLocal<Integer> threadLocalValue = new Thr...

程序那些事 1万+

Java之ThreadLocal

1ThreadLocal接口出现原因 使用ThreadLocal保存当前线程的变量值,这样你想获取该变量的值的时候,获取到的都是本线程的变量值,不会获取到其他线程设置的值,早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序 2 接口主...

码莎拉蒂 2813

【Java 集合】ThreadLocal

在多线程编程中,我们经常面临共享数据的问题,而这可能引发一系列并发性和线程安全性的挑战。Java 提供了许多机制来处理这些问题,比如控制并发的各种锁, 控制线程串行地修改资源, 避免线程安全, 或者通过关键字 volatile 修饰变量, 保证可见性等。而在解决并发共享的方式中, 还有一种方式, 那么就是线程隔离, 每个线程各自维护资源的副本, 从而避免了共享资源的竞争。

LCN29的博客 1212

常用类库----ThreadLocal类

ThreadLocal 在多线程并发执行中,为了可以准确的实现每个线程中的数据成员访问,可以通过java.lang.ThreadLocal类实现数据的保存与获取 ThreadLocal类是在多线程并发访问时使用,所以在数据保存时除了保护用户所需要的数据外,还会额外保存一个当前的线程对象,而在获取数据时也将通过当前线程对象来获取保存的数据内容,这样可以保证多线程并发访问下的数据操作安全。 ThreadLocal最大的特点就是可以同时保存多个线程的数据,由于每个数据都有对应的当前线程对象,这样就可以保证数据

ll_j_21的博客 168

Java并发工具之ThreadLocal

ThreadLocal 字面意思是本地线程,其实更准确来说是线程局部变量,线程类 Thread 有个变量叫做 threadLocals,其类型就是ThreadLocal.ThreadLocalMap 类型,他其实不是一个 Map 类型,但可以暂时理解它是一个Map,键为 ThreadLocal 对象,值就是要存入的value。

Qynwang的博客 6543

Java的ThreadLocal

Java的ThreadLocal

duke_ding2的博客 889

Java里的线程神器:ThreadLocal

今天我们要学习一种在JAVA线程中至关重要的类——ThreadLocal。ThreadLocal是一个强大的JAVA类,它能实现线程局部变量的功能。通过ThreadLocal,每一个线程都可以拥有自己的一份变量副本,互相之间不会影响操作,真正做到数据隔离。尤其在多线程环境下,避免了线程间混乱的数据共享、避免出现竞争条件,使得编程更加优雅。

编码人生 1044

Java中的ThreadLocal详解

多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。

mrhubobo的博客 1449
上一篇: Java常用类:异常看这篇就够了
下一篇: Java常用类:Class类
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值