当前位置: 首页 > news >正文

ThreadLocal基本介绍

文章目录

  • 什么是ThreadLocal
    • ThreadLocal解决了什么问题
    • ThreadLocal的作用
  • ThreadLocal的使用场景
    • ThreadLocal的代码示例
    • ThreadLocal的优点
    • ThreadLocal的缺点
    • 与volatile、synchronized、ThreadLocal比较
  • 总结

什么是ThreadLocal

ThreadLocal是Java中的一个线程本地变量,它提供了一种在多线程环境下保持变量的副本,每个线程都可以独立地修改自己的副本,而不会影响其他线程的副本。

ThreadLocal解决了什么问题

在多线程环境下,共享变量的访问可能会引发线程安全问题。例如,多个线程同时访问同一个变量时,可能会导致数据的不一致性和竞态条件。ThreadLocal提供了一种解决方案,通过为每个线程提供独立的副本,避免了共享变量的竞争和同步问题,从而解决了线程安全问题。

ThreadLocal的作用

ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

作者:安仔夏天勤奋
链接:https://www.jianshu.com/p/6fc3bba12f38
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

ThreadLocal的使用场景

ThreadLocal适用于以下场景:

数据库连接管理:每个线程需要独立的数据库连接,可以使用ThreadLocal来管理每个线程的连接。
用户身份认证:每个线程需要独立的用户身份信息,可以使用ThreadLocal来存储用户的身份信息。
线程上下文传递:多个方法之间需要共享一些上下文信息,可以使用ThreadLocal来传递上下文信息。

ThreadLocal的代码示例

下面是一个使用ThreadLocal的简单示例,用于存储用户的身份信息:

public class UserContext {private static final ThreadLocal<User> userThreadLocal = new ThreadLocal<>();public static void setUser(User user) {userThreadLocal.set(user);}public static User getUser() {return userThreadLocal.get();}public static void clearUser() {userThreadLocal.remove();}
}public class User {private String name;// ... 其他属性和方法
}public class Main {public static void main(String[] args) {User user1 = new User("Alice");User user2 = new User("Bob");UserContext.setUser(user1);System.out.println(UserContext.getUser().getName()); // 输出:AliceUserContext.setUser(user2);System.out.println(UserContext.getUser().getName()); // 输出:BobUserContext.clearUser();System.out.println(UserContext.getUser()); // 输出:null}
}

在上面的示例中,UserContext类使用ThreadLocal来存储用户的身份信息。通过调用setUser方法来设置当前线程的用户信息,调用getUser方法来获取当前线程的用户信息,调用clearUser方法来清除当前线程的用户信息。

ThreadLocal的优点

线程隔离:每个线程都有自己独立的变量副本,不会受其他线程的影响,实现了线程间的隔离。
简单易用:使用ThreadLocal非常简单,只需要创建一个ThreadLocal对象,并调用其get和set方法即可。
高效性:ThreadLocal使用了线程的ThreadLocalMap来存储变量副本,访问速度快。

ThreadLocal的缺点

内存泄漏:如果ThreadLocal变量没有及时清理,可能会导致内存泄漏。因为ThreadLocalMap中的Entry会持有ThreadLocal对象的强引用,如果ThreadLocal对象没有被及时回收,就会造成内存泄漏。
线程间数据共享困难:ThreadLocal只能在当前线程内共享数据,在线程间传递数据相对困难,需要借助其他方式(如参数传递)来实现。

与volatile、synchronized、ThreadLocal比较

在这里插入图片描述

在简单变量读写场景中,使用volatile关键字可以保证变量的可见性和禁止指令重排序,但不涉及锁竞争。

在复杂的线程同步和互斥场景,synchronized关键字提供了安全且经过测试的机制来实现线程间的互斥。但需要注意锁的竞争和上下文切换会带来性能开销。

ThreadLocal提供了一种简单的方式来实现线程间的变量隔离和线程上下文传递。它通过为每个线程提供独立的变量副本,避免了锁竞争,并且不涉及上下文切换,访问速度较快。但需要注意及时清理ThreadLocal变量,避免内存泄漏。

综上所述,选择合适的机制取决于具体的使用场景。对于简单的变量读写场景,可以使用volatile关键字。对于复杂的线程同步和互斥场景,synchronized提供了可靠的机制。而ThreadLocal则特别适用于需要变量隔离和线程上下文传递的场景,可以提供简单且高效的解决方案。

总结

在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。 初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。 然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。

实际的通过ThreadLocal创建的副本是存储在每个线程自己的threadLocals中的;

为何threadLocals的类型ThreadLocalMap的键值为ThreadLocal对象,因为每个线程中可有多个threadLocal变量,就像上面代码中的longLocal和stringLocal;

在进行get之前,必须先set,否则会报空指针异常;如果想在get之前不需要调用set就能正常访问的话,必须重写initialValue()方法。 因为在上面的代码分析过程中,我们发现如果没有先set的话,即在map中查找不到对应的存储,则会通过调用setInitialValue方法返回i,而在setInitialValue方法中,有一个语句是T value = initialValue(), 而默认情况下,initialValue方法返回的是null。

http://www.lryc.cn/news/112703.html

相关文章:

  • ffmpeg源码编译成功,但是引用生成的静态库(.a)报错,报错位置在xxx_list.c,报错信息为某变量未定义
  • 2023爱分析·信创云市场厂商评估报告:中国电子云
  • 网络安全学习笔记——XFF攻击流程
  • 微信小程序阻止用户返回上一页,并弹窗给用户确定是否要返回上一页
  • LangChain+ChatGLM整合LLaMa模型(二)
  • 【NLP】训练chatglm2的评价指标BLEU,ROUGE
  • java+springboot+mysql员工工资管理系统
  • FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版
  • 探索Python数据容器之乐趣:列表与元组的奇妙旅程!
  • Python自动化实战之使用Pytest进行API测试详解
  • TCP的三次握手以及四次断开
  • 目标检测YOLO实战应用案例100讲-基于视觉与激光雷达信息融合的智能车辆目标检测研究
  • Day 22 C++ STL常用容器——string容器
  • 使用Socket实现UDP版的回显服务器
  • 【MCU学习】GD32F427VG开发
  • Acwing.877 扩展欧几里得算法
  • 基于自组织竞争网络的患者癌症发病预测(matlab代码)
  • golang mongodb
  • docker中的jenkins去配置sonarQube
  • 企业如何实现自己的AI垂直大模型
  • Maven可选依赖和排除依赖简单使用
  • “深入探索JVM:Java虚拟机的工作原理解析“
  • Prometheus-各种exporter
  • 小程序的 weiui的使用以及引入
  • git目录初始化,并拉取最新代码
  • 运筹调度算法工程式招聘情况:技能要求、薪资、工作地
  • css2-BFC是什么?
  • Flutter Dart语言(04)库操作
  • 通向架构师的道路之漫谈使用ThreadLocal改进你的层次的划分
  • springboot全局统一返回处理