首页 > 编程语言 >【Java】深入解析ThreadLocal——Java并发编程的秘密武器

【Java】深入解析ThreadLocal——Java并发编程的秘密武器

时间:2024-09-21 14:22:59浏览次数:11  
标签:Java Thread get 秘密武器 ThreadLocal 线程 数据 public

        ThreadLocal 被称为线程局部变量,用于在线程中保存数据。由于在 ThreadLocal中保存的数据仅属于当前线程,所以该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。

        ThreadLocal 用于在同一个线程间,在不同的类和方法之间共享数据的的场景,也可以用于在不同线程间隔离数据的场景。

        ThreadLocal利用 Thread 中的 ThreadLocalMap 来进行数据存储。

一、常用方法

1. 存储数据至当前线程的 ThreadLocalMap:public void set(T value)

2. 从当前线程的 ThreadLocalMap 中获取数据:public T get()

3. 从当前线程的 ThreadLocalMap 中删除数据:public void remove()

        在线程池的线程复用场景中,线程执行完毕时一定要调用remove(),避免在线程被重新放入线程池中时被本地变量的旧状态仍然被保存。

        ThreadLocal的get()方法、set()方法和remove()方法,其实最终操作的都是 ThreadLocalmap 类中的数据。

二、ThreadLocalMap内部结构

        ThreadLocalMap 内部数据结构是一个 Entry 类型的数组。每个 Entry 对象的 key为 ThreadLocal对象,value 为存储的数据

三、为什么用ThreadLocal做key

        如果在应用中,一个线程中只使用了一个ThreadLocal 对象,那么使用 Thread做 key 也是可以的,代表每个 Thread 线程对应一个 value 。

        但是,在实际应用程序开发过程中,一个线程中很有可能不只使用了一个ThreadLocal 对象。这时使用 Thread 做 key 就会产生混淆

        所以,不能使用 Thread 做 key ,而应该改成用 ThreadLocal 对象做 key,这样才能通过具体 ThreadLocal对象的get()方法,获取到当前线程的 ThreadLocalMap,然后进一步获取到对应的Entry。

public class Test {
    private static ThreadLocal<String> namethreadLocal = new ThreadLocal();
    private static ThreadLocal<String> idthreadLocal = new ThreadLocal();

    public static void main(String[] args) {

        Thread t1 = new Thread(()->{
            try{
                // 保存数据
                namethreadLocal.set("马超");
                idthreadLocal.set("001");

                // 调用方法,查看获取数据
                dosth();
            }finally {
                namethreadLocal.remove();
                idthreadLocal.remove();
            }
        });

        Thread t2 = new Thread(()->{
            try{
                namethreadLocal.set("马云");
                idthreadLocal.set("008");
                dosth();
            }finally {
                namethreadLocal.remove();
                idthreadLocal.remove();
            }
        });

        t1.start();
        t2.start();

    }
    public static void dosth(){
        // 通过threadLocal,获取当前线程中的数据
        String name = namethreadLocal.get();
        System.out.println(Thread.currentThread().getName()+"-dosth:"+name);

        String id = idthreadLocal.get();
        System.out.println(Thread.currentThread().getName()+"-dosth:"+id);

        // 线程继续调用方法,获取当前线程的数据
        show();
    }

    public static void show(){
        // 通过threadLocal,获取当前线程中的数据
        String name = namethreadLocal.get();
        System.out.println(Thread.currentThread().getName()+"-show:"+name);

        String id = idthreadLocal.get();
        System.out.println(Thread.currentThread().getName()+"-show:"+id);
    }

}

四、父子线程如何共享数据

        在实际工作中,有可能需要在父子线程共享数据的。即:在父线程中往 ThreadLocal 设置了值,在子线程中能够获取到。

        使用JDK自带的InheritableThreadLocal类,该类继承了ThreadLocal

// 父子线程传递数据
public class Test{
    public static void main(String[] args) {

        // ThreadLocal threadLocal = new ThreadLocal();  // 子线程不能获取父线程数据
        InheritableThreadLocal threadLocal = new InheritableThreadLocal(); // 子线程可以获取父线程数据

        threadLocal.set("天王盖地虎");
        System.out.println(Thread.currentThread().getName()+"主线程:"+threadLocal.get());

        Thread t = new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"子线程:"+threadLocal.get());
        });
        t.start();
    }
}

五、ThreadLocal应用场景

1. 线程数据隔离

        ThreadLocal 的主要价值在于线程隔离,ThreadLocal 中的数据只属于当前线程,该数据对别的线程是不可见的,起到隔离作用。这样操作,可以在多线程环境下,可以防止当前线程的数据被其他线程修改。另外,由于各个线程之间的数据相互隔离,避免了同步加锁带来的性能损失,大大提升了并发性的性能。

        例如:sqlSession会话对象绑定,避免多个线程使用同一个sqlsession 对象,由于关闭导致异常。


2. 跨函数传递

        数据通常用于同一个线程内,跨类、跨方法传递数据时,如果不用ThreadLocal,那么相互之间的数据传递势必要靠返回值和参数,这样无形之中增加了这些类或者方法之间的耦合度。



        

标签:Java,Thread,get,秘密武器,ThreadLocal,线程,数据,public
From: https://blog.csdn.net/weixin_71491685/article/details/142390482

相关文章

  • Java Stream流编程入门
    流式编程stream流式编程分为首先转化为stream中间函数的链接最后的终结函数怎么转化为stream单列集合List<String>list=newArrayList<String>();Collections.addAll(list,"1","2","3","4","5","6","7","8"......
  • Java中set接口的学习
    Set接口目录Set接口HashSetTreeSetLinkedHashSetEnumSetCopyOnWriteArraySetHashSetJava中的HashSet是集合框架中非常重要的一个类,它实现了Set接口,提供了存储不重复元素的功能。特点无序性:HashSet不保证元素的顺序,即元素的存储顺序与插入顺序无关。遍历HashSet的结果是无序......
  • Java入门:09.Java中三大特性(封装、继承、多态)02
    2继承需要两个类才能实现继承的效果。比如:类A继承类BA类称为子类,衍生类,派生类B类称为父类,基类,超类继承的作用子类自动的拥有父类的所有属性和方法(父类编写,子类不需要再编写)。代码复用目前私有的属性和方法无法访问。多态的基础。继承语法先定义父......
  • Java基本语法
    Java基本语法注释单行注释//多行注释/**/文档注释/***/快捷方法psvm为加入方法sout为输出Shift+Alt+.为放大字体Shift+Alt+,为减小字体标识符号不能用关键字作为变量名或方法名![关键字](file:///C:/Users/15200/Downloads/Screenshot_202......
  • Java免税商品购物商城:Spring Boot实现详解
    第一章绪论1.1课题开发的背景从古至今,通过书本获取知识信息的方式完全被互联网络信息化,但是免税商品优选购物商城,对于购物商城工作来说,仍然是一项非常重要的工作。尤其是免税商品优选购物商城,传统人工记录模式已不符合当前社会发展和信息管理工作需求。对于仓储信息管理......
  • 【JAVA开源】基于Vue和SpringBoot的在线文档管理系统
    本文项目编号T038,文末自助获取源码\color{red}{T038,文末自助获取源码}......
  • 【JAVA开源】基于Vue和SpringBoot的网上超市系统
    本文项目编号T037,文末自助获取源码\color{red}{T037,文末自助获取源码}......
  • 基于JavaWeb的原神游戏商城的设计与实现
    目录博主介绍:......
  • 2025届必看:Java SpringBoot搭建大学生资助管理系统,详解功能模块,实现学生信息高效管理!
    ✍✍计算机毕业编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、微信小程序、大数据实战项目集⚡⚡文末......
  • 如何打造动漫插画分享社区?Java SpringBoot助力,Vue前端开发,2025最新毕业设计推荐!
    ✍✍计算机毕业编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、微信小程序、大数据实战项目集⚡⚡文末......