线程一直挂在Socket / Printwriter交互上

时间:2013-02-13 18:17:48

标签: java sockets printwriter

我的程序运行了一段时间(大约20秒)之后它发送的消息越来越少,直到它停止。我做了一个Thread转储,它指向了线程停止的以下代码行:

if(s.isClosed() || !s.isConnected() || s.isInputShutdown() || s.isOutputShutdown() || out == null || out.checkError()) {

这是我的线程转储的一部分

    "class xxx.xxx.xxx" prio=10 tid=0x000000000200d800 nid=0x6e7f waiting for monitor entry [0x00007f63172b6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at java.io.PrintWriter.flush(PrintWriter.java:291)
        - waiting to lock <0x00000000ec810218> (a java.io.BufferedWriter)
        at java.io.PrintWriter.checkError(PrintWriter.java:330)

此线程转储信息指出问题出在Printwriter.checkError()中。但我无法理解为什么它会停在这里。

以下是其上下文中的代码。 (接收者是Map<Socket, PrintWriter>

public void parseMessage(final byte[] bytes) {
    synchronized (receivers) {
        for (final Socket s : receivers.keySet()) {
            final PrintWriter out = receivers.get(s);
            if(s.isClosed() || !s.isConnected() || s.isInputShutdown() || s.isOutputShutdown() || out == null || out.checkError()) {
                receivers.remove(s);
                failedToConnect(s.getInetAddress().getHostAddress(), s.getPort());
                continue;
            }
            queue.add(out, bytes);
        }
    }
}

更新14 januari(格林威治标准时间10:00 + 1):

PrintWriter

替换BufferedWriter

更新14 januari(格林尼治标准时间16:00 + 1):

我已经运行了一些测试,结果发现某些网络/读卡器之间的某种通信问题导致了麻烦。该应用程序将数据发送到其内部网络中的某些读者,以及某些外部网络中的某些读者(通过互联网)。究竟是什么导致这一点在这一点上仍然未知,但有一些线索。几次重启后,我可以看到两个网络之间没有关闭的连接,所以连接保持打开状态。我仍然不知道这里到底发生了什么,但它在我看来是某种网络问题。在服务器端,连接保持在“FIN_WAIT1”,在阅读器端,它保持“ESTABLISHED”。看起来即使已经发送信号关闭它,读卡器也不会发出关闭连接信号的信号。

2 个答案:

答案 0 :(得分:1)

if(s.isClosed() || !s.isConnected() || s.isInputShutdown() || s.isOutputShutdown() || out == null || out.checkError())

这是一系列无用的测试。

  • 如果套接字已关闭,则根本不应该在代码的这一部分中。
  • 如果没有连接套接字,同上。
  • 如果您已关闭套接字输入,则并不意味着您无法写入。
  • 如果您已关闭套接字输出,则不应该在代码的这一部分。
  • 如果out为空,则不应该在代码的这一部分。
  • 测试checkError()很好,但您根本不应该在网络上使用PrintWriter,因为它会吞下异常。最好使用BufferedWriter并让异常告诉你发生错误的事情,而不是你在这里做的下一次写作。

您还需要了解Socket.isClosed()仅告诉您是否已关闭Socket.同样,Socket.isConnected()仅告诉您已连接{ {1}}或已通过构造函数或Socket,收到它。同样适用于ServerSocket.accept()isInputShutdown()他们只告诉您对isOutputShutdown().做了什么。这些方法都没有告诉您有关连接状态的任何信息。

  

此线程转储信息指出问题出在Printwriter.checkError()中。但我无法理解为什么它会停在这里。

因为,正如堆栈跟踪也告诉你的那样,它正在调用Socket.如果阻塞它意味着你已经超出了读者,并且TCP正在等待他读取一些数据来释放他的套接字中的缓冲区空间缓冲区因此你的套接字发送缓冲区。在此之前,基础flush().将会阻止。除了加速读者之外,你无能为力。

答案 1 :(得分:0)

当线程被阻塞时,它很可能正在等待I / O请求 看看这个链接,它与你正在经历的非常相似 how-to-analyze-java-thread-dumps