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

多线程环境下JsonPath 2.9.0返回错误值,寻求解决办法及替代方案

JsonPath 2.9.0线程安全问题分析与解决方案

问题根源

这确实是JsonPath 2.9.0本身的问题。JsonPath的JsonPath.read()静态方法内部会复用全局的配置/上下文实例,这些实例并非线程安全,多线程并发调用时会出现上下文污染,导致不同线程的数据互相串用,就像你测试里出现的Babara50、John48这类交叉结果。

应对方法

  • 为每个线程创建独立的JsonPath上下文
    不要使用静态的JsonPath.read(),手动为每个线程创建专属的Configuration和JsonPath实例,避免共享上下文:

    private Runnable createRunnable(String json) {
        return () -> {
            int count = 10;
            // 每个线程初始化独立的配置与JsonPath实例
            Configuration config = Configuration.defaultConfiguration();
            JsonPath jsonPath = JsonPath.compile("concat($.person.name, $.person.age)");
            try {
                while (count > 0) {
                    count--;
                    Thread.sleep(1000);
                    String value = jsonPath.read(json, config);
                    if (value.equals("John48") || value.equals("Babara50")) {
                        System.out.println("Wrong value returned: " + value);
                    }
                    System.out.printf("Thread-[%d], Value: [%s]%n", Thread.currentThread().getId(), value);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
    }
    
  • 升级JsonPath版本
    后续的JsonPath稳定版本(如高于2.9.0的版本)对线程安全问题做了修复优化,升级到最新稳定版可直接解决这类问题,注意升级后验证原有功能兼容性。

  • 用ThreadLocal管理线程隔离的上下文
    若需要复用上下文同时保证线程隔离,可通过ThreadLocal存储每个线程的Configuration或JsonPath实例:

    private static final ThreadLocal<JsonPath> JSON_PATH_THREAD_LOCAL = ThreadLocal.withInitial(
        () -> JsonPath.compile("concat($.person.name, $.person.age)")
    );
    
    private static final ThreadLocal<Configuration> CONFIG_THREAD_LOCAL = ThreadLocal.withInitial(
        Configuration::defaultConfiguration
    );
    
    private Runnable createRunnable(String json) {
        return () -> {
            int count = 10;
            try {
                while (count > 0) {
                    count--;
                    Thread.sleep(1000);
                    String value = JSON_PATH_THREAD_LOCAL.get().read(json, CONFIG_THREAD_LOCAL.get());
                    if (value.equals("John48") || value.equals("Babara50")) {
                        System.out.println("Wrong value returned: " + value);
                    }
                    System.out.printf("Thread-[%d], Value: [%s]%n", Thread.currentThread().getId(), value);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 可选:线程结束时清理ThreadLocal,避免内存泄漏
                JSON_PATH_THREAD_LOCAL.remove();
                CONFIG_THREAD_LOCAL.remove();
            }
        };
    }
    

原测试代码与运行结果

原测试代码

@Test
public void testJsonPath() throws IOException {

  String jsonString = "{\"test\":1,\"person\":{\"name\":\"John\",\"age\":50}}";
  String jsonString2 ="{\"test\":1,\"person\":{\"name\":\"Babara\",\"age\":48}}";
  Thread thread1 = new Thread(createRunnable(jsonString));
  Thread thread2 = new Thread(createRunnable(jsonString2));
  thread1.start();
  thread2.start();
  try {
    thread1.join();
    thread2.join();
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}

private Runnable createRunnable(String json) {
  return () -> {
    int count = 10;
    try {
      while (count > 0) {
        count--;
        Thread.sleep(1000);
        String value = JsonPath.read(json, "concat($.person.name, $.person.age)");
        if (value.equals("John48") || value.equals("Babara50")) {
          System.out.println("Wrong value returned: " + value);
        }
        System.out.printf("Thread-[%d], Value: [%s]%n", Thread.currentThread().getId(), value);

      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  };
}

原运行结果

Thread-[30], Value: [John50]
Thread-[31], Value: [Babara48]
Thread-[30], Value: [John50]
Thread-[31], Value: [Babara48]
Thread-[31], Value: [Babara48]
Thread-[30], Value: [John50]
Thread-[31], Value: [Babara48]
Thread-[30], Value: [Babara50]
Thread-[31], Value: [John48]
Thread-[30], Value: [John50]
Thread-[31], Value: [Babara48]
Thread-[30], Value: [Babara50]
Thread-[30], Value: [John50]
Thread-[31], Value: [John48]
Thread-[31], Value: [John48]
Thread-[30], Value: [John50]
Thread-[31], Value: [Babara48]
Thread-[30], Value: [John50]
Thread-[31], Value: [Babara48]
Thread-[30], Value: [John50]

内容的提问来源于stack exchange,提问作者PhuTa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:00:32