0

Java アプリケーションを閉じようとしていますが、スレッドが開いたままになっています。

デフォルトのWindows xボタンを使用して閉じるをクリックすると、すべてが正常に終了します(おそらくEXIT_ON_CLOSEが原因ですか?)-しかし、プログラムボタンを使用すると、thread.join()でハングします。

さらに悪いことに、ウィンドウは正常に処理されているため、ユーザーはウィンドウが閉じていると思いますが、開いたままの AWT スレッドがいくつかあります。私のメイン スレッドは ID が 20 のスレッドを待機していますが、スレッド ID を取得する方法がわかりません。

誰か提案はありますか?

これが私の終了コードです:

public synchronized void stop() {
    running = false;
    frame.dispose();
    WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
    try {
        if (server != null) {
            server.exit();
        }
        client.exit();
        thread.join();
        new Thread(){
            public void run() {
                System.exit(0);
            }
        }.start();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        e.printStackTrace();
        System.exit(1);
    }
}

終了後に開いているスレッドは次のとおりです。

スレッドエクリプス

run()ここに私のメソッドの内容があります:

public void run() {
    requestFocus();
    while (running) {
        getTimer().tick();
        if (System.currentTimeMillis() - getTimer().getSecond() > 1000) {
            // every second, add a second, print fps and mod title with fps
            getTimer().accumulateSecond();
            //System.out.println(getTimer().returnFPS());
            frame.setTitle(title + "  |  " + getTimer().returnFPS());
            getTimer().resetTick();
            ticker++;
        }
        while (getTimer().getDelta() >= 1) {
            // every time delta goes greater than one, update and supertick
            update();
            getTimer().superTick();
        }
        if (getTimer().getFPS() > 100) {
            try {
                Thread.sleep(5);
            } catch (Exception e) {
                System.err.println("Sleeping failed: " + e);
            }
        } 
        render();
        if (ticker > 30) {
            ticker = 0;
            getTimer().hourTick();
        }

    }
    stop();
}
4

1 に答える 1

0

アップデート:

あなたのコードをもっと見た後、あなたの問題はあなたが1つのスレッドから呼び出しstop()ていることだと確信しています。synchronizedstop()で を呼び出します。これは、インスタンスがそのメソッドを終了thread.join()するのを待機しようとします。フラグを設定するとループが終了しますが、メソッドの最後のコード行は への別の呼び出しです。これがあなたが示した方法と同じである場合、デッドロックが発生しています。threadrun()runningrun()whilestop() stop()

メソッド内のstop()呼び出しは、最初のスレッドがまだ内部にあり、完了するのを待っているrun()ため、メソッドに入ることができません(呼び出して入ることができるのを待っているため、メソッドに入ることができません)。デッドロック。stop()run()stop()

stop()内からへの呼び出しを削除するrun()か、コードを作り直す別の方法を見つける必要があります。


特定のスレッド ID を識別することについて心配する必要はありません。すべてのスレッドが適切に完了することを心配してください。

まず、スレッドを停止Thread#join()しません。完了するのを待ちます。あなたがしている他の何かは、インスタンスがそのメソッドを完了するようにする/許可する必要があります。threadrun()

これを行うことができる唯一のことは、設定です

    running = false;

オブジェクトはそのメソッドthread内でそのフラグをチェックしていますか? run()例えば:

public void run() {
    while (isRunning()) {

        // do some work
        Thread.sleep(delay);
    }
}

変数の値はどこisRunning()に返されますか?running

今、私はあなたのコードをもっと見ずに言うことはできません. isRunning()ただし、次のように実装することを選択した可能性があります。

public synchronized boolean isRunning() {
    return running;
}

そんなことをしたら、問題が発生します。メインスレッドは、stop()あなたが示した方法でロックを取得します。次に、thread.join()呼び出しに到達し、その時点でワーカー スレッドの待機を開始します。次に、ワーカー スレッドisRunning()が同じロックで同期されている を呼び出すとisRunning()、メイン スレッドが内部にあるためにロックがすでに保持されているため、 がブロックされstop()ます。

オブジェクトが、あなたが示したコードを持つクラスからthread他のsynchronizedメソッドを呼び出そうとすると、同じ基本的な問題が発生する可能性があります。

thread簡単に言えば、さらにコード (変数によって表されるスレッドで実行されているもの) を確認する必要があります。しかし、ここでデッドロックに達した可能性があります。

スレッドの正常な停止について詳しくは、こちらをご覧ください

于 2013-05-31T01:56:11.020 に答える