实例变量在高并发下必须严格约束,不可变字段、atomicinteger、sealed interface事件模型、threadlocal/对象池及禁止构造期/lambda中暴露this是保障线程安全的核心手段。

实例变量本身不能“不受捕获限制”——恰恰相反,**在高并发下,实例变量正是最需要被严格约束的对象**。所谓“不受捕获限制”是一种常见误解;真实情况是:只要方法引用或 lambda 捕获了 this 或其字段,而该对象又未完全构造、未做线程隔离、或被跨线程共享,实例变量就会成为逃逸源和竞态温床。
用不可变实例变量定义状态机起点
状态机的“状态”应来自不可变字段,而非可变实例变量。例如:
- 定义 public static final int INIT = 0, RUNNING = 1, DONE = 2,而非用
int status字段直接读写 - 将状态变量声明为
private final AtomicInteger status = new AtomicInteger(INIT),利用其 CAS 能力实现原子转换 - 避免在构造器中初始化状态后又被外部修改——构造即终态,后续只允许通过受控方法变更
用 record + sealed interface 封装状态迁移事件
把每一次状态变化建模为不可变事件对象,而非修改实例字段:
- 定义
sealed interface TaskEvent permits TaskStarted, TaskCompleted, TaskFailed - 每个事件是
record TaskStarted(Instant at, String operator) implements TaskEvent - 状态机核心逻辑用
switch (event) -> { ... }穷尽匹配,编译期强制覆盖所有迁移路径 - 事件对象天然不可变,不暴露 this,不引发逃逸,多线程可安全传递与消费
用 ThreadLocal 或对象池隔离可变上下文
若业务确需临时状态(如格式化上下文、计算缓存),绝不复用实例变量,而是按需绑定到执行单元:
- 对轻量上下文,用
ThreadLocal<formattercontext></formattercontext>,每次请求独享一份 - 对重资源上下文(如 AI 推理会话),用
GenericObjectPool<discountcontext></discountcontext>管理,借还分离、自动复位 - 线程池任务中显式获取 → 使用 → 归还,不持有引用、不跨任务共享
禁止在构造过程或 lambda 中暴露实例变量
这是逃逸高频发生点,必须切断链路:
- 不在构造器中调用
executor.submit(this::handle)或eventBus.register(this) - 不写
executor.submit(() -> counter++)(counter 是实例字段);改用final int local = this.counter.get(); executor.submit(() -> process(local)) - 所有对外发布的方法引用,都封装成 final 局部变量:
final Runnable task = () -> doWork(data); executor.submit(task);










