1

テキストを変更したため、一部のコメントは以前のバージョンを参照している可能性があります

以下はコードサンプルです。オブザーバーとオブザーバブルの 2 つのスレッドがあります。Observable は main によって開始されます。オブザーバーは、観察可能なオブジェクトの作成によって開始され、その破壊で終了することを意図しています。しかし、それは起こらず、オブザーバーは永遠に実行されます。なんで?

public class ThreadObjectReaping01 {

private static final Logger log = LoggerFactory.getLogger(ThreadObjectReaping01.class);

public static void main(String[] args) throws InterruptedException {

    Thread observable = new Thread("observable") {

        private Thread observable2 = this;

        Thread observer = new Thread("observer") {
            @Override
            public void run() {

                log.info("Observer is starting");

                while(!interrupted()) {

                    if( observable2.isAlive() ) {
                        log.info("Observable is running");
                    }
                    else {
                        log.info("Observable is NOT running");
                    }

                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        interrupt();
                    }
                }

                log.info("Observer is terminating");

            }
        };

        {
            observer.start();
        }

        @Override
        protected void finalize() throws Throwable {
            observer.interrupt();
        }

        @Override
        public void run() {

            log.info("Observable is starting");

            while(!interrupted()) {
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    interrupt();
                }
                //log.info("Observable is running");
            }


        }
    };

    log.info("Main is starting observable");
    observable.start();
    Thread.sleep(10000);
    log.info("Main is interrupting observable");
    observable.interrupt();
    observable = null;
    Thread.sleep(10000);
    log.info("Main is terminating");

}
}
4

2 に答える 2

2

メインオブジェクト(オーバーライドしているオブジェクト)に到達finalize()できなくなった(ガベージコレクションの対象となる)と、GCが最初に呼び出します。追跡しているようですので、ログメッセージが実際に呼び出されていることを確認してください。finalize()

ただし、かろうじて呼び出すinterrupt()だけでは不十分ですが、デーモンスレッドは(を使用してisInterrupted())そのフラグをアクティブにチェックし、正しく応答して、できるだけ早くシャットダウンする必要があります。また、もしあれば正しく処理する必要がありInterruptedExceptionます。

スレッドがデーモンスレッドであるという事実は関係ありません。非デーモンスレッドがJVMの終了を妨げています(JVMは、すべての非デーモンスレッドが作業を終了したときに存在します)。ここでは、スレッドを手動で中断しています。そのスレッドがデーモンであるかどうかは関係ありません。

これは単なるガベージコレクターの遅延ですか、それともレポーターによって参照されているためにメインオブジェクトが削除されないため、スレッドが実際に終了することはありませんか?

あなたの"Reporting of..."メッセージは表示されたことがありますか?そこにブレークポイントを置くことができます。これは、実装するオブジェクトfinalize()がGCの犠牲者であったことを意味します。スレッドのみreporterがメインオブジェクトへの参照を保持している場合(およびその逆)、循環依存にもかかわらず、外部で参照されていないオブジェクトがない場合でも、GCはこれらのオブジェクトを解放します。

参照:

ポストスクリプトム

あなたの質問とは関係ありません。を使用している場合、これは次のとおりです。

log.info(String.format("Reporting of (%s) is about ot interrupt", getName()));

次のように置き換えることができます:

log.info("Reporting of {} is about to interrupt", getName());
于 2012-07-26T17:26:59.350 に答える
2

メインスレッドでコーディングされているにもかかわらず、レポータースレッドが終了しないことに気づきました

run()スレッドは、例外または戻りのためにメソッドを終了すると終了します。あなたが話しているならthread.interrupt()、これは単に割り込みフラグを設定し、いくつかのメソッド(sleep、wait、...)にをスローさせInterruptedExceptionます。スレッドで、割り込みフラグをテストする必要があります。

while (!Thread.currentThread().isInterrupted()) {
     // here's how you should be catching InterruptedException
     try {
        ...
     } catch (InterruptedException e) {
        // re-enable the interrupted flag
        Thread.currentThread.interrupt();
        // probably you should quit the thread too
        return;
     }
}

スレッドが終了しThread、オブジェクト自体への参照がなくなると、スレッドはガベージコレクターによって取得されます。mainにまだThread threadフィールドがある場合、ガベージコレクションされることはありません。

ところで、finalize特にログを記録して他のことをしている場合は、使用をお勧めしません。スレッドが終了したときにその種のクリーンアップを実行する独自のdestroy()メソッドまたはそのようなメソッドが必要です。多分次のようなものです:

 public void run() {
     try {
        // do the thread stuff
     } finally {
        destroy();
     }
 }
于 2012-07-26T17:27:03.277 に答える