【问题标题】:Java client / server thread null pointer exception when quickly communicating messages快速通信消息时Java客户端/服务器线程空指针异常
【发布时间】:2013-10-05 00:12:15
【问题描述】:

我正在使用 JavaFX 创建一个简单的信使客户端。有问题的类是:

MainMenuController.class:该类处理 JavaFX ui 逻辑,例如将聊天消息打印到文本区域

Server.class:控制服务器套接字和输入/输出逻辑

Client.class:控制客户端套接字和输入/输出逻辑

我能够在本地主机上完美地运行应用程序,但当我尝试发送消息过快时,我的程序会抛出空指针异常。我将通过相关代码,然后我将解释我尝试解决此错误的方法。

MainMenuController.java(异常追踪到这个函数)

public static void printMessage(String sender, String msg) {
    //msgHistory is a textArea
    msgHistory.appendText(sender + ": " +msg + "\n");
}

服务器.java

try {
    servSocket = new ServerSocket(serverPort);

    MainMenuController.printMessage("Server running on port: "
        + serverPort + ". . .");

    // block till we accept connection request
    clientSocket = servSocket.accept();

    out = new PrintWriter(clientSocket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader(
        clientSocket.getInputStream()));

    // receive and set friend's alias
    friendName = in.readLine();
    aliasSet = true;

    String input;

    // while connection is present, poll server socket input for new
    // messages
    while (true) {
        Thread.sleep(100);
        input = in.readLine();

        if (input == null) {
            break;
        }

        //update status 
        MainMenuController.printMessage(friendName, input);  //Line traced to exception
    }
}

Client.java

try {   
    socket = new Socket (serverAddr, portNum);

    MainMenuController.printMessage("Connected!");

    out = new PrintWriter(socket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    //send server our alias
    out.println(myName);

} catch (IOException e) {
    System.err.println("Accept failed.");
}

我认为异常是由于客户端和服务器试图同时写入 MainMenuController 中的 textArea 引起的。我已经尝试在服务器打印到 textArea 之前添加一个 thread.sleep(x)。我还在 MainMenuController 类中实现了一个公共锁。在服务器和客户端中对 printMessage 的每次调用中,我都会等到锁释放后再调用 printMessage 方法(我在调用 printMessage 之前设置了锁,然后在方法返回后释放它)。我把这段代码拿出来使它更具可读性。这些解决方案都没有奏效,我不知道该去哪里找。

堆栈跟踪:

Exception in thread "Thread-4" java.lang.NullPointerException
    at com.sun.javafx.sg.prism.NGTextHelper$TextAttributes.computeLinePadding(NGTextHelper.java:405)
    at com.sun.javafx.sg.prism.NGTextHelper$TextAttributes.access$200(NGTextHelper.java:292)
    at com.sun.javafx.sg.prism.NGTextHelper.buildTextLines(NGTextHelper.java:2357)
    at com.sun.javafx.sg.prism.NGTextHelper.validateText(NGTextHelper.java:1847)
    at com.sun.javafx.sg.prism.NGTextHelper.getCaretShape(NGTextHelper.java:1435)
    at javafx.scene.text.Text.getDecorationShapes(Text.java:1150)
    at javafx.scene.text.Text.impl_geomChanged(Text.java:757)
    at javafx.scene.text.Text$1.invalidated(Text.java:214)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:127)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
    at javafx.scene.text.Text.setText(Text.java:188)
    at com.sun.javafx.scene.control.skin.TextAreaSkin$17.invalidated(TextAreaSkin.java:610)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:359)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
    at javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1034)
    at javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1038)
    at javafx.scene.control.TextInputControl$TextProperty.invalidate(TextInputControl.java:978)
    at javafx.scene.control.TextInputControl$TextProperty.access$200(TextInputControl.java:950)
    at javafx.scene.control.TextInputControl$1.invalidated(TextInputControl.java:119)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
    at javafx.scene.control.TextArea$TextAreaContent.insert(TextArea.java:196)
    at javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:373)
    at javafx.scene.control.TextInputControl.insertText(TextInputControl.java:308)
    at javafx.scene.control.TextInputControl.appendText(TextInputControl.java:298)
    at application.MainMenuController.printMessage(MainMenuController.java:96)
    at application.Server.run(Server.java:79)
    at java.lang.Thread.run(Unknown Source)

编辑:此错误仅发生在 textArea.appendText(string) 中。 textArea.setText(string) 不会抛出异常。

【问题讨论】:

  • 发布堆栈跟踪。

标签: java multithreading sockets javafx


【解决方案1】:

您不应该从任意线程调用 JavaFX 方法,而只能从 JavaFX 应用程序线程调用。将您的 msgHistory.appendText 封装在 Platform.runLater() 调用中。

【讨论】:

  • 这行得通,谢谢!我有一个后续问题:我收到此错误:无法在以不同方法定义的内部类中引用非最终变量 msg。我通过为 printMessage() 的 sender 和 msg 参数创建两个临时的最终字符串来解决这个问题。有没有更有效的解决方法?
  • 可以直接将方法参数声明为final。我不认为有真正的效率提升,但它不那么混乱。
【解决方案2】:

您没有检查 friendName 是否为空。任何readLine() 调用都可以返回null。

NB 在调用readLine() 之前睡觉确实是在浪费时间。它会阻塞直到数据可用。

【讨论】:

  • 当客户端连接时,它会发送一条包含好友别名的消息。这是在 while 循环之前在 Server 类的字段中设置的。我不认为这是问题的根源,因为异常总是在对话中发生几条消息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
相关资源
最近更新 更多