You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gson Type Adapter是否线程安全?多线程下BigDecimal序列化异常问题

问题解决:多线程下ThreadLocal导致BigDecimal序列化异常

核心原因

线程池复用线程时,ThreadLocal中残留的scale值未被清理,导致原本不需要格式化的请求意外获取到之前请求设置的scale,触发了setScale(scale, RoundingMode.FLOOR)逻辑,将金额错误序列化为带固定小数位的形式(比如0.0)。

解决方案

在所有设置过ThreadLocal scale值的代码路径中,使用try-finally块强制清理ThreadLocal,确保线程复用不会携带旧值:

1. 完善ThreadLocalContextUtil工具类

确保工具类提供明确的清理方法:

public class ThreadLocalContextUtil {
    private static final ThreadLocal<Integer> FRACTIONAL_DIGITS = new ThreadLocal<>();

    public static Integer getFractionalDigits() {
        return FRACTIONAL_DIGITS.get();
    }

    public static void setFractionalDigits(Integer scale) {
        FRACTIONAL_DIGITS.set(scale);
    }

    // 新增ThreadLocal清理方法
    public static void removeFractionalDigits() {
        FRACTIONAL_DIGITS.remove();
    }
}

2. 在业务代码中强制清理

所有需要设置scale的请求处理逻辑,必须在finally块中清理ThreadLocal,无论请求成功或失败:

// 示例:需要格式化金额的API处理逻辑
public ResponseEntity<?> processAmountRequest() {
    try {
        // 设置当前请求需要的小数位数
        ThreadLocalContextUtil.setFractionalDigits(2);
        // 执行业务逻辑,触发BigDecimal序列化
        BigDecimal amount = new BigDecimal("100");
        return ResponseEntity.ok(amount);
    } finally {
        // 强制清理ThreadLocal,避免线程复用残留旧值
        ThreadLocalContextUtil.removeFractionalDigits();
    }
}

3. (可选)适配器中增加防御性校验

如果担心极端场景下清理不及时,可以在适配器中增加校验,仅当scale为合法有效值时才执行格式化逻辑,作为兜底方案:

@Override
public void write(final JsonWriter out, final BigDecimal value) throws IOException {
    if (value == null) {
        out.nullValue();
        return;
    }
    final var scale = ThreadLocalContextUtil.getFractionalDigits();
    // 仅当scale为非负有效值时才格式化,避免意外的0或负数导致的错误序列化
    if (scale != null && scale >= 0) {
        final var newVal = value.setScale(scale, RoundingMode.FLOOR);
        out.value(newVal);
    } else {
        out.jsonValue(value.toPlainString());
    }
}

关键说明

ThreadLocal实现线程隔离,但线程池中的线程会被重复使用,如果不主动清理,线程持有的ThreadLocal值会一直存在,直到线程被销毁或被新值覆盖。这是多线程环境下使用ThreadLocal的常见陷阱,必须通过try-finally确保资源清理。

内容的提问来源于stack exchange,提问作者Chếnhếng Seang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 15:40:59