文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

ThreadLocal如何在Java中使用

2023-06-15 02:07

关注

本篇文章给大家分享的是有关ThreadLocal如何在Java中使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

1. 应用场景

ThreadLocal 的常见应用场景有两种:

  1. 多线程并发场景中,用来保障线程安全。

  2. 处理较为复杂的业务时,使用ThreadLocal代替参数的显示传递。

1.1. 保障线程安全

多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性,如:synchronized、Lock之类的锁。

ThreadLocal是除了加锁这种同步方式之外的一种,规避多线程访问出现线程不安全的方法。当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量,这样就不会存在线程不安全问题。

ThreadLocal是JDK包提供的,它提供线程本地变量,如果创建一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的是自己本地内存中的变量,从而规避了线程安全问题。

1.2. 显示传递参数

这里举几个例子:

示例1:获取接口的当前请求用户
在后台接口业务逻辑的全过程中,如果需要在多个地方获取当前请求用户的信息。通常的一种做法就是:在接口请求时,通过过滤器、拦截器、AOP等方式,从session或token中获取当前用户信息,存入ThreadLocal中。

在整个接口处理过程中,如果没有另外创建线程,都可以直接从ThreadLocal变量中获取当前用户,而无需再从Session、token中验证和获取用户。这种方案设计不仅提高性能,最重要的是将原本复杂的逻辑和代码实现,变得简洁明了。例如下面的这个例子:

(1)定义ThreadLocal变量:UserProfileThread.java

public class UserProfileThread {    private static ThreadLocal<UserProfile> USER_PROFILE_TL =new ThreadLocal<>();    public static void  setUserProfile(UserProfile userProfile){        USER_PROFILE_TL.set(userProfile);    }    public static UserProfile getUserProfile() {        return USER_PROFILE_TL.get();    }    public static String getCurrentUser() {        return Optional.ofNullable(USER_PROFILE_TL.get())                .map(UserProfile::getUid)                .orElse(UserProfile.ANONYMOUS_USER);    }}

(2)在过滤器中设置变量值:

   @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        UserProfile userProfile = null;        // ... 验证和获取用户信息 userProfile        UserProfileThread.setUserProfile(userProfile);        filterChain.doFilter(servletRequest, servletResponse);    }

(3)获取当前用户信息

//获取当前用户String uid=UserProfileThread.getCurrentUser();//获取当前用户对象UserProfile user=UserProfileThread.getUserProfile();

示例2:spring框架中保证数据库事务在同一个连接下执行

要想实现jdbc事务, 就必须是在同一个连接对象中操作,多个连接下事务就会不可控,需要借助分布式事务完成。那spring框架如何保证数据库事务在同一个连接下执行的呢?

DataSourceTransactionManager 是spring的数据源事务管理器,它会在你调用getConnection()的时候从数据库连接池中获取一个connection, 然后将其与ThreadLocal绑定,事务完成后解除绑定。这样就保证了事务在同一连接下完成。

2. 实现原理

ThreadLocal类提供set/get方法存储和获取value值,但实际上ThreadLocal类并不存储value值,真正存储是靠ThreadLocalMap这个类。

每个线程实例都对应一个TheadLocalMap实例,我们可以在同一个线程里实例化很多个ThreadLocal来存储很多种类型的值,这些ThreadLocal实例分别作为key,对应各自的value,最终存储在Entry table数组中。
我们看看ThreadLocal的set方法:

public class ThreadLocal<T> { public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }    ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }    void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }    // 省略其他方法}

set的逻辑比较简单,就是获取当前线程的ThreadLocalMap,然后往map里添加KV,K是当前ThreadLocal实例,V是我们传入的value。这里需要注意一下,map的获取是需要从Thread类对象里面取,看一下Thread类的定义。

public class Thread implements Runnable {    ThreadLocal.ThreadLocalMap threadLocals = null;    //省略其他}

Thread类维护了一个ThreadLocalMap的变量引用。

因此,我们可以得出如下结论:

  1. 每个线程是一个Thread实例,其内部维护一个threadLocals的实例成员,其类型是ThreadLocal.ThreadLocalMap。

  2. ThreadLocal本身并不是一个容器,我们存取的value实际上存储在ThreadLocalMap中,ThreadLocal只是作为TheadLocalMap的key。

3. 注意事项

ThreadLocal实例有提供remove()方法,用于回收对象,清除对应的内存占用。这个方法通常容易被忽略,而导致出现了各种问题。如下面几种:

Java的优点是什么

1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程序;2. 面向对象;3. 分布性,Java是面向网络的语言;4. 鲁棒性,java提供自动垃圾收集来进行内存管理,防止程序员在管理内存时容易产生的错误。;5. 安全性,用于网络、分布环境下的Java必须防止病毒的入侵。6. 体系结构中立,只要安装了Java运行时系统,就可在任意处理器上运行。7. 可移植性,Java可以方便地移植到网络上的不同机器。8.解释执行,Java解释器直接对Java字节码进行解释执行。

以上就是ThreadLocal如何在Java中使用,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯