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

分布式网络节点开发中wait()引发的空指针及非法监视器异常排查

问题分析与修复方案

服务器端IllegalMonitorStateException根源与修复

你在synchronized(lock)代码块里直接调用wait(),这其实是调用当前对象(this)的wait()方法,但当前线程持有的是lock对象的监视器锁,不是this的,所以必然抛出IllegalMonitorStateException——这就是服务器端报错的直接原因。

修复很简单:必须调用同步锁对象的wait(),也就是把wait()改成lock.wait()。

修改后的等待代码:

while (node == 1)
{
    synchronized (lock) {
        try {
            lock.wait(); // 改成lock.wait(),和同步对象对应
            System.out.println("I waited.");
            node = 2;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("This is a thread error.");
        }
    }
    System.out.println("And the Wait Ended.");
    response = Response.newBuilder()
            .setResponseType(Response.ResponseType.REPLY)
            .setMessage("You waited.")
            .build();
    // 别忘了把响应发给客户端!
    response.writeDelimitedTo(out);
}

客户端空指针异常的解决

客户端的NullPointerException是因为:服务器端进入等待状态后,没有向客户端发送第二个响应,客户端调用Response.parseDelimitedFrom(in)时,输入流没有数据,方法返回null,后续调用response.getMessage()自然触发空指针。

两步修复:

  1. 客户端读取响应前先判空,避免直接调用方法;
  2. 服务器端唤醒后必须把响应写入输出流发给客户端(上面的代码已经加了response.writeDelimitedTo(out))。

修改后的客户端代码:

try {
    // connect to the server
    serverSock = new Socket(host, port);

    // write to the server
    out = serverSock.getOutputStream();
    in = serverSock.getInputStream();

    op.writeDelimitedTo(out);

    // read from the server
    response = Response.parseDelimitedFrom(in);

    // 先检查响应是否有效
    if (response != null) {
        System.out.println(response.getMessage());
    } else {
        System.err.println("服务器未返回有效响应");
        return;
    }
    
    // wait on the server
    response = Response.parseDelimitedFrom(in); 
    if (response != null) {
        System.out.println(response.getMessage());
    } else {
        System.err.println("服务器未返回等待后的响应");
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    // 关闭资源
    if (in != null)   in.close();
    if (out != null)  out.close();
    if (serverSock != null) serverSock.close();
}

额外提醒

  • 确保lock是所有处理该客户端的线程共享的实例,每个线程新建lock的话,同步和等待唤醒完全没用;
  • 别用忙等待,wait()/notifyAll()是正确的线程协作方式,修复监视器问题后就能正常工作;
  • 你处理InterruptedException时恢复中断状态的代码是对的,不用改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:05:24