0

クライアント コードが終了しないのはなぜですか? (クライアントを実行する前に、まずサーバー プログラムを開始する必要があります)

サーバーコード:

public class ServerSocketTest {

    static final int PORT = 9999;

    public static void main(String[] args) throws IOException {
        final ServerSocket serverSocket = new ServerSocket(PORT);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        while (true) {
            final Socket socket = serverSocket.accept();
            Runnable runnable = new Runnable() {

                @Override
                public void run() {
                    System.out.println(socket);
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
        }

    }

}

クライアントコード:

public class SocketClient {

    public static void main(String[] args) throws UnknownHostException,
            IOException {
        final Socket socket = new Socket("localhost", ServerSocketTest.PORT);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("waiting to close socket " );
                printThread(Thread.currentThread());
                try {                   
                    socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("waiting to exit");
                printThread(Thread.currentThread());                
                System.exit(0);
            }
        });
    }

    static void printThread(Thread currentThread) {
        System.out.println(currentThread + ": Alive=" + currentThread.isAlive()
                + ",Daemon=" + currentThread.isDaemon());
    }
}

Ubuntuを使用しています。jconsole を使用して、次のスレッドとその他の RMI および JMX スレッドをトレースできました。


名前: 参照ハンドラの状態: java.lang.ref.Reference$Lock@14f38ff で待機中 総ブロック: 1 総待機: 2

スタックトレース:

java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:503)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)

名前: ファイナライザー状態: java.lang.ref.ReferenceQueue$Lock@3037a0 で待機中合計ブロック: 1 待機合計: 2

スタックトレース:

java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

名前: シグナル ディスパッチャー 状態: RUNNABLE 合計ブロック: 0 合計待機: 0

スタックトレース:


名前: DestroyJavaVM 状態: net.SocketClient$2@39b27b で待機中 総ブロック: 0 総待機: 1

スタックトレース:

java.lang.Object.wait(Native Method)
java.lang.Thread.join(Thread.java:1258)
java.lang.Thread.join(Thread.java:1332)
java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106)
java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
java.lang.Shutdown.runHooks(Shutdown.java:123)
java.lang.Shutdown.sequence(Shutdown.java:167)
java.lang.Shutdown.shutdown(Shutdown.java:234)
- locked java.lang.Class@127bd04

名前: Thread-1 (これは、System.exit を呼び出すために追加したシャットダウン フックです) 状態: BLOCKED on java.lang.Class@127bd04 所有者: DestroyJavaVM 合計ブロック: 1 合計待機: 0

スタックトレース:

java.lang.Shutdown.exit(Shutdown.java:212)
java.lang.Runtime.exit(Runtime.java:107)
java.lang.System.exit(System.java:960)
net.SocketClient$2.run(SocketClient.java:31)

名前: SIGINT ハンドラー (これは Control+C が押されると生成されるようです) 状態: BLOCKED on java.lang.Class@127bd04 所有者: DestroyJavaVM 合計ブロック: 1 合計待機: 0

スタックトレース:

java.lang.Shutdown.exit(Shutdown.java:212)
java.lang.Terminator$1.handle(Terminator.java:52)
sun.misc.Signal$1.run(Signal.java:212)
java.lang.Thread.run(Thread.java:722)
4

3 に答える 3

0

シャットダウン フックで System.exit() を呼び出す必要はありません。おそらくデッドロックまたは無限再帰が発生する可能性があるため、これを行うべきではありません。他のものも必要ありません。スレッドをデーモン スレッドにする方がよいでしょう。

于 2012-07-22T05:35:33.187 に答える
0

ライブ スレッド (フック) が実行されているため、停止しません。それともJavaプロセスにSIGTERMやSIGINTシグナルを送っても止められないということですか?

于 2012-07-21T07:10:16.277 に答える
0

ここで使用する意味がわからないaddShutdownHook。ドキュメントから:

シャットダウン フックもすばやく作業を終了する必要があります。プログラムが exit を呼び出すと、仮想マシンがすぐにシャットダウンして終了することが期待されます。ユーザーのログオフまたはシステムのシャットダウンが原因で仮想マシンが終了した場合、基盤となるオペレーティング システムは、シャットダウンして終了するために一定の時間しか許可しない場合があります。したがって、シャットダウンフックでユーザーとの対話を試みたり、長時間実行される計算を実行したりすることはお勧めできません。

socket.close()コードを閉じる機会がなかった場合、OS が自動的に終了するため、終了する必要はありません。シャットダウンフックをまったく使用せずにコードを再構築しようとします。

于 2012-07-21T07:15:06.827 に答える