0

基本的に2つの無限ループスレッドといくつかのGUI(Swing)を持つマルチスレッドプログラムがあります。私の 2 つの無限ループ スレッドには、次のような独自の log4j ロガーがあります。

    static final Category LOG = Category.getInstance(RReceiver.class);

GUI で終了キーを検出したら、System.exit(0) を実行します。

public boolean dispatchKeyEvent(KeyEvent e) {
    if (e.getKeyCode()!=27 && e.getKeyCode()!=KeyEvent.VK_BACK_SPACE) return false; 
    System.exit(0);
    return true;
}

コンソールでの効果は次のようになります。

DEBUG 13:07:00,940 [Receiver] (RReceiver.java:93) - 応答 len:38 を取得
DEBUG 13:07:01,044 [Receiver] (RReceiver.java:93) - 応答 len:38 を取得
DEBUG 13:07:01,045 [レシーバー] (RReceiver.java:93) - 新しいステータス dev 4
log4j:WARN ロガー (com.normantech.ibcol.radiobox.RReceiver) のアペンダーが見つかりませんでした。
log4j:WARN log4j システムを適切に初期化してください。

警告は常に表示されるわけではありません。間違った初期化シーケンスがあると思われますが、それを理解できません。なぜそれが起こっているのですか?LogManager.shutdown(); を使用しようとしました。しかし、それは役に立ちませんでした。私は無限ループをうまく終わらせようとしましたが、それは最善の解決策ではありません.IIは追加の Thread.sleep(x) を配置する必要があり、別の x を試しましたが、これが役立つかどうかは実際にはわかりませんでした.

4

1 に答える 1

2

根本的な問題は、スレッドを正常にシャットダウンするのではなく、System.exit() を呼び出してスレッドを強制終了していることです。これは、他のすべてが閉じられた後でも、JVM が実際にプロセスを終了する前に非常に短時間実行し続ける可能性があることを意味します。その間に共有状態 (ロギング システムなど) を使用すると、矛盾した状態または壊れた状態になる可能性があります。シャットダウンされている可能性があります。これは適切な方法ではありません ( http://www.javapractices.com/topic/TopicAction.do?Id=86を参照)。

これを解決する方法は、共有リソース (ロギング システム) をシャットダウンする前に、スレッドを適切にシャットダウンすることです。ただ system.exit() を呼び出す代わりに、各スレッドに停止する時が来たことを伝え、停止するのを待ちます。これを行う最もクリーンな方法は、ループごとにブール値をチェックしrunning、ループを停止するときにそのブール値を外部で false に設定することです。次に、スレッドがこのブール値に気づき、特定のスレッド インスタンスで Thread.join() を呼び出すか、終了finished時にスレッドにブール値を設定させることで終了するのを待つことができます (これらのブール値を両方とも揮発性としてマークするのが最善です)。

ループの各反復に時間がかかる場合、または含まれているwait()sleep()呼び出している場合は、ループ中に実行中のブール値をより頻繁にチェックするか、Thread.interrupt().

これが完了し、他のすべてのスレッドが停止したことを確認したら、プロセスを呼び出しLogManager.shutdown()て実際に終了できます。

于 2013-04-23T12:27:31.213 に答える