在Ja va多线程服务中,想要快速定位那些隐藏的数据竞争点,避免因共享变量未同步导致的偶发性结果错乱、空指针异常或集合扩容时的诡异崩溃,Fitten Code插件算是一个趁手的工具。它可以帮你精准扫描并发风险,具体需要重点关注这么几类问题:Shared mutable field、线程安全容器替换、Lambda闭包捕获,以及CompletableFuture上下文同步。

静态扫描识别高危共享对象
操作很直接:打开Fitten Code插件侧边栏 → 点击「Find Bug」→ 在弹出的窗口顶部切换到「Concurrency Risk」标签页。然后把光标放到待检类名上(比如UserService),按快捷键Ctrl+Shift+B(Windows/Linux)或Cmd+Shift+B(macOS),就能触发深度并发扫描。
扫描结果里,所有被标记为【Shared mutable field】的成员变量都必须立刻处理——这类字段如果被多个CompletableFuture或线程池任务直接读写,十有八九会引发数据竞争。举个典型的例子:private List,这种写法在并发调用时必然崩溃,没得商量。
自动注入线程安全容器
处理方式有两种。第一种:对已报红的非线程安全集合字段,右键选择「Fix with Thread-Safe Alternative」,插件会自动替换为CopyOnWriteArrayList或ConcurrentHashMap。第二种:如果字段需要保持原有语义(比如既要有序插入又要线程安全),Fitten Code会建议改用Collections.synchronizedList(new ArrayList<>()),但这里有个关键点——必须包裹所有遍历操作,否则迭代期间仍然存在被修改的风险。
这一步不能偷懒:手动检查生成代码中所有的for-each循环,确认是否已经套上了synchronized(cache) { ... }结构。但凡漏掉一处,隐患就依然潜伏着。
检测并修复Lambda闭包捕获问题
先说第一步:在CompletableFuture.supplyAsync()内部,检查是否直接引用了外部方法的局部变量(比如String token = getAuthToken();然后supplyAsync(() -> callApi(token)))。
第二步:如果这个变量在supplyAsync执行前已经被外部线程修改了,那闭包内拿到的值就完全不可控。Fitten Code会在变量名下方标黄,并提示「Captured variable may change before execution」。
第三步:点击灯泡图标 → 选择「Capture immutable snapshot」,插件会自动生成final String safeToken = token;,并把lambda体内的token全部替换为safeToken。
这一步是关键的防线:不加final修饰的局部变量捕获,在JVM内存模型下可见性是无法保证的,很容易出现空指针或脏读。
验证CompletableFuture链式调用的线程上下文
选中整个CompletableFuture链(从supplyAsync开始到join/thenApply结束),右键 → 「Analyze Execution Context」。
Fitten Code会绘制出线程流转图:如果发现thenAccept()块中间出现了System.out.println(user.getName())这类无锁操作,而上游又有多个supplyAsync在并行写入同一个对象,插件会立即标红警告。
这时候必须插入显式同步:把user.getName()替换为synchronized(user) { user.getName(); },否则在高并发压测下就会随机出现NullPointerException——因为user对象很可能正被另一线程置为null。
