3

そのため、私はこの問題に丸一日苦労しており、いくつかのスレッド化チュートリアルと例を参照しても、まだ目的の結果を達成できていません。

私は、文字列の LinkedBlockingQueue をポーリングし、PrintWriter を使用してソケット経由で文字列をクライアントに配信することだけを行うスレッドを持っています。その機能は正常に動作していますが、接続の中断と再起動が発生した場合に適切に失敗できるようにすることで、機能を強化しようとしています. これを実現するために、スレッドで割り込みを呼び出してから参加し、Thread オブジェクトを再作成して最初からやり直すことを最終目標にしています。残念ながら、スレッドは join の呼び出しでハングします。これは、スレッドが実際に死ぬことは決してないことを意味するに違いありませんが、なぜそうなのかについて私は完全に当​​惑しています。以下の関連コード。

try {
    resultSetStreamer.interrupt();
    resultSetStreamer.join();
    logger.info("Streamer finished.");
} catch (InterruptedException e) {}

実際のスレッド コード。

class ResultSetStreamer implements Runnable {

    GZIPOutputStream gzos = null;
    Socket clientSocket = null;

    @Override
    public void run() {

        try {
            logger.debug("Thread started.");

            // Blocks and waits for an external connection.
            clientSocket = serverSocket.accept();

            // Creates a compression stream using best possible compression
            // to the external connection.
            gzos = new GZIPOutputStream(clientSocket.getOutputStream()) {
                {
                    def.setLevel(compression);
                }
            };
            PrintWriter toClient = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(gzos), bufferSize), false);

            while (true) {
                if (Thread.interrupted()) {
                    throw new InterruptedException();
                }
                if (moreRowsToReceive || !dataBuffer.isEmpty()) {
                    // Synchronisation point.
                    String row = dataBuffer.poll(pollTime,
                            TimeUnit.MILLISECONDS);
                    if (row != null) {
                        toClient.println(row);
                        logger.trace("Current row: " + ++currentCount + ".");
                    }
                } else {
                    toClient.flush();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                gzos.finish();
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.debug("Thread finished.");
    }
}

注目すべき主な場所は while(true) ループです。これは常にループし、スレッドが中断されたかどうかを確認する必要があります。その場合、スレッドを終了させるために、下部でキャッチされる例外をスローします。PrintWriter がコードの実行をブロックするべきではないと思います。どんな助けでも大歓迎です。

4

2 に答える 2

2

JVM は、スレッドを終了するために割り込みを強制しません。コードが呼び出すすべてのブロッキング呼び出しが割り込みをサポートしていることを確認する必要があります。

たとえば、クライアントがデータを受信して​​いない場合、出力バッファーがいっぱいになり、toClient.println() がブロックされますが、この呼び出しは割り込みをサポートしていないため、.interrupt() を呼び出しても終了しません。

デバッグ ログを追加して、コード ブロックの正確な場所を特定することをお勧めします。

于 2012-07-03T17:02:57.647 に答える
1

実行しているマシンで、jconsoleを起動し、実行中のプログラムに接続してみてください。[スレッド]タブで、各スレッドをクリックして、現在実行されていることを確認できるはずです。これにより、Runnableオブジェクトのどのステートメントがまだ完了していないかがわかります。

于 2012-07-03T18:42:01.517 に答える