2

私のプログラムはしばらく (約 20 秒) 実行された後、停止するまで送信するメッセージの数が減っていきます。スレッド ダンプを作成したところ、スレッドが停止する次のコード行が表示されます。

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);
        }
    }
}

1 月 14 日更新 (10:00 GMT+1):

をに置き換えましPrintWriterBufferedWriter

1 月 14 日更新 (16:00 GMT+1):

さらにいくつかのテストを実行したところ、一部のネットワーク/リーダー間の何らかの通信の問題が問題を引き起こしていることが判明しました。アプリケーションは、内部ネットワークの一部のリーダーにデータを送信し、一部の外部ネットワークの一部のリーダーに (インターネット経由で) データを送信しています。正確な原因は現時点では不明ですが、いくつかの手がかりがあります。数回再起動した後、2 つのネットワーク間の接続が閉じられていないため、接続が開いたままになっていることがわかりました。ここで正確に何が起こっているのかはまだわかりませんが、何らかのネットワークの問題のようです。サーバー側では接続は「FIN_WAIT1」のままで、リーダー側では「ESTABLISHED」のままです。リーダーは、接続を閉じるための信号が送信されたとしても、接続を閉じるための信号を送信しないようです。

4

2 に答える 2

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

これはほとんど無駄な一連のテストです。

  • ソケットが閉じている場合は、コードのこの部分にいるべきではありません。
  • ソケットが接続されていない場合も同様です。
  • 入力用のソケットをシャットダウンしても、書き込みができないわけではありません。
  • 出力用のソケットをシャットダウンした場合は、コードのこの部分にいるべきではありません。
  • ifoutが null の場合、コードのこの部分にいるべきではありません。
  • テストは優れていますが、例外を飲み込んでしまうため、実際にはネットワーク経由でcheckError()使用するべきではありません。ここで行っているように次の書き込みではなく、例外PrintWriterを使用して、問題が発生したときに例外を通知する方がよいでしょう。BufferedWriter

同様に、を閉じたSocket.isClosed()どうかのみを通知し、 を接続したか、またはコンストラクターを介して既に接続されていることを通知するだけであることも理解する必要があります。同じことが当てはまります。これらのメソッドのどれも、接続の状態について何も教えてくれません。Socket.Socket.isConnected()Socket,ServerSocket.accept()isInputShutdown()isOutputShutdown().Socket.

このスレッド ダンプ情報は、問題が Printwriter.checkError() にあることを示しています。しかし、なぜここで停止するのか理解できません。

flush().スタック トレースからもわかるように、 If を呼び出しているため、それはリーダーがオーバーランしたことを意味し、TCP は彼がデータを読み取ってソケット受信バッファーのバッファー スペースを解放し、ソケット送信バッファーを解放するのを待っています。それが起こるまで、基礎となるものsend()はブロックされます。リーダーをスピードアップする以外に、それについてできることは何もありません。

于 2013-02-14T00:34:36.090 に答える
0

スレッドがブロックされている場合、I/O 要求を待っている可能性が最も高いです。このリンクを見てください。これは、 Java スレッド ダンプを分析する方法と非常によく似ています。

于 2013-02-13T18:43:25.380 に答える