线程封闭的核心是让数据仅在单线程内使用以避免同步问题,栈封闭是最自然的实现方式,局部变量天生线程安全;需防范引用逃逸,必要时用ThreadLocal跨方法持有线程私有对象。

线程封闭的核心,就是让数据只在一个线程里打转——不共享,就不用锁,也不用担心可见性或竞态。而栈封闭,正是最自然、最常用、也最值得优先使用的线程封闭方式。
局部变量天生就是线程安全的
每次方法调用,JVM都会在线程自己的栈帧中分配独立空间来存放局部变量。不同线程调用同一个方法,彼此看到的只是自己栈里的那一份副本,完全隔离。
- 安全写法:int count = 0; count++; —— 每个线程都有自己的count,互不干扰
- 危险写法:private int counter;(成员变量)—— 多线程共用一个内存地址,结果不可控
- 引用类型同理:TreeSet<Animal> animals = new TreeSet<>(...); 只要这个引用不出方法作用域,对象就始终被封闭在当前线程内
小心“逃逸”:别让局部变量跑出方法边界
局部变量的安全,前提是它不被发布出去。一旦把引用赋给静态字段、作为参数传给其他线程、或存入共享容器,封闭性立刻失效。
- 避免返回可变集合本身,可考虑返回Collections.unmodifiableSet(animals)
- 不要在方法内把局部对象赋值给类的实例变量或static字段
- 构造临时对象时,优先选用不可变类型(如LocalDateTime、String),减少意外修改风险
什么时候该换ThreadLocal?
当需要跨多个方法、跨越多次调用、甚至贯穿整个请求生命周期持有某个对象时,局部变量就力不从心了。比如格式化日期、传递用户上下文、维护数据库连接。
- 推荐用ThreadLocal.withInitial()初始化,比重写initialValue()更简洁清晰
- 在线程池场景下,务必在使用后调用remove(),防止内存泄漏
- 不要把它当成全局变量的替代品——它的存在意义是“每个线程一份”,不是“所有线程共用一份”

















