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

Java多线程wait/notify无法传递JSONObject问题咨询

问题核心原因

JSONObject 完全支持在线程间通过 wait/notify 机制传递,你遇到的问题和对象类型是 JSONObject 还是自定义业务类没有任何关系,本质是代码里的锁对象根本不是同一个实例。

你代码里的错误点非常明确:

  • 第一个线程中你先初始化了一个空的JSONObject实例赋值给jobj_gnss,但在JSON解析完成后,你将jobj_gnss变量重新指向了parser.parse()返回的全新JSONObject实例。后续你加锁、调用notifyAll()操作的都是这个新生成的解析结果对象,和最开始创建的空JSONObject没有任何关联。
  • 第二个线程中的jobj_gnss变量没有做任何初始化:如果是局部变量,这段代码直接编译不通过;如果是成员变量,默认值为null,直接对null做synchronized加锁会直接抛出空指针异常。就算你提前把第二个线程的jobj_gnss赋值为第一个线程最开始创建的空JSONObject实例,两个线程操作的也不是同一个锁:第一个线程notify的是解析生成的新对象,第二个线程wait的是最开始的空对象,永远收不到通知,自然拿不到解析后的数据。

你之前测试自定义业务类能正常运行,只是因为你没有在同步逻辑里重新给共享变量赋值换对象,两个线程始终在同一个实例上做wait/notify,和对象类型无关。

修正实现方案

不要用业务数据对象当锁,单独定义一个不可变的专门锁对象,同时用独立的共享变量存储解析结果,从根源上避免锁对象引用变更的问题:

首先定义两个线程共享的变量:

// 专用锁对象,初始化后永远不重新赋值
private final Object lock = new Object();
// 共享变量存储解析后的JSON结果,volatile保证跨线程可见性
private volatile JSONObject jsonResult = null;

数据获取线程(第一个线程)代码:

String testingProcess="{\"navi\":{\"longitude\":9.015089833333333,\"latitude\":45.514222999999997,\"altitude\":151.9,\"speed\":78.2,\"travelAngle\":244.08,\"horp\":2.52,\"vertp\":5.699999999999999},\"status\":{\"locked\":true,\"quality\":2,\"type\":3,\"gps_time\":\"10h 57m 20s  October 13 2020\",\"satellites_tracked\":12,\"satellites_in_view\":15},\"res\":\"OK\"}";
JSONParser parser = new JSONParser();      
try {
    jsonResult = (JSONObject) parser.parse(testingProcess);
} catch (ParseException e) {
    e.printStackTrace();
}       
// 始终锁固定的lock对象
synchronized (lock) {    
    lock.notifyAll();
}

数据处理线程(第二个线程)代码:

synchronized (lock) {
    // 必须用while循环判断条件,防止虚假唤醒
    while (jsonResult == null) {
        try {
            lock.wait();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return;
        }
    }
    // 走到这里说明结果已经准备完成,直接处理即可
    System.out.println(jsonResult.toString());
    // 后续持久化到文件的逻辑
}

额外注意事项

  • 永远不要把可能被重新赋值的变量指向的对象作为synchronized锁,否则极易出现锁不一致导致的通知丢失、死锁问题。
  • 调用wait()等待条件时必须用while循环判断业务状态,不能用if判断,避免线程虚假唤醒后在条件未满足的情况下继续执行。
  • 跨线程访问的共享变量建议加volatile修饰,保证一个线程对变量的修改对其他线程立即可见,避免JMM可见性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:03:24