十三、ThreadLocal
一、什么是ThreadLocal
ThreadLocal,提供线程局部变量。这些变量与正常的变量不同,因为每个线程在访问ThreadLocal实例的时候(通过其get或set方法)都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态字段,使用它的目的是希望将状态(例如,用户lD或事务ID)与线程关联起来。
二、为什么要用ThreadLocal
实现每一个线程都有自己专属的本地变量副本,主要解决了让每个线程绑定自己的值,通过使用get()和set()方法,获取默认值或将其值更改为当前线程所存的副本的值从而避免了线程安全问题。
三、Demo
public class ThreadLocalDemo { public static void main(String[] args) { House house = new House(); new Thread(() -> { try { for (int i = 1; i <= 15; i++) { house.saleHouse(); } System.out.println(Thread.currentThread().getName() + "\t" + "-- - 卖出:" + house.threadLocal.get()); } finally { house.threadLocal.remove(); } }, "AA").start(); new Thread(() -> { try { for (int i = 1; i <= 10; i++) { house.saleHouse(); } System.out.println(Thread.currentThread().getName() + "\t" + "-- - 卖出:" + house.threadLocal.get()); } finally { house.threadLocal.remove(); } }, "BB").start(); System.out.println(Thread.currentThread().getName() + "\t" + "-- - 卖出:" + house.threadLocal.get()); } } class House { ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0); public void saleHouse() { Integer value = threadLocal.get(); value++; threadLocal.set(value); } }
四、总结
1、使用完后必须remove()回收自定义的ThreadLocal变量,尤其在线程池场景下,线程经常会被复用,如果不清理自定义的ThreadLocal变是,可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用try-finally块进行回收。
2、ThreadLocalMap从字面上就可以看出这是一个保存ThreadLocal对象的map(其实是以ThreadLocal为Key),不过是经过了两层包装的ThreadLocal对象:
JVM内部维护了一个线程版的Map<Thread,T>(通过ThreadLocal对象的set方法,结果把ThreadLocal对象自己当做key,放进了ThreadLoalMap中),每个线程要用到这个T的时候,用当前的线程去Map里面获取,通过这样让每个线程都拥有了自己独立的变量,
人手一份,竞争条件被彻底消除,在并发模式下是绝对安全的变量
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)