2

私は一般的に、デーモンを実装するための2つのアプローチを見てきました。デーモンは、いくつかの作業を実行し、スリープ状態になり、再びウェイクアップします。

  1. while(flag)アプローチ。ここで、flagはtrueであり、デーモンを停止する場合は他のクラスによってfalseに設定されます。

    while(flag){
       //do something
       Thread.sleep(10000l);
    }
    
  2. 固定遅延を使用したScheduledThreadPoolExecutorによるスケジューリング。

IMO、2番目のアプローチは、はるかにクリーンでテストが簡単です。誰かがこれらの2つのアプローチを比較できますか?最初のアプローチはメモリの問題を引き起こす可能性がありますか?

ありがとう

4

2 に答える 2

3

最初のアプローチでメモリの問題が発生する可能性はありますか?

いいえ。最大の問題は、flag変数の可視性を管理することです。誰かがその方法論を提案しているのを見るたびに、私は即座に反対票を投じます。このThreadクラスは、何らかの理由で割り込みフラグの概念をカプセル化しています。

于 2013-02-21T09:58:15.050 に答える
2

アプローチ 2) をお勧めします。

アプローチ 1 は、基礎となるスレッド システム (特に UNIX の場合) によるランダムな覚醒に対して堅牢ではなく、独自のエラー処理を実装する必要もあります。

アプローチ 2 では、基になるものから抽象化Threadし、Runnableorを操作できますCallable

さらに、アプローチ 1) にはクロック ドリフトの問題があります。つまり、タスクの実行にゼロ以外の時間がかかるため、10 秒ごとに実行されません。は、ScheduledExecutorService実際には 1 秒ごとに、または必要に応じて 10 秒間隔で実行をスケジュールします。

アプローチ 2) は、スレッドが一定期間何かを実行するようにスケジュールする簡単な方法を提供し、javadocの例に従ってスレッドを強制終了します。

最後に、カスタム スレッドをシャットダウンして、最後のタスクが終了するまで待機する方ExecutorSeviceがはるかに簡単です。executorService.shutdown()executorService.awaitTermination()

注意したいことの 1 つは、javadoc のこの gem です - 「タスクの実行で例外が発生した場合、後続の実行は抑制されます」。これは、非常に注意する必要があるか、したがってサブクラス化する必要があることを意味try/catchします(javadoc から取得):CallableScheduledExecutorService

public class MyScheduledExecutor extends ScheduledThreadPoolExecutor {

    public MyScheduledExecutor(int corePoolSize) {
        super(corePoolSize);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t == null && r instanceof Future<?>) {
            try {
                Object result = ((Future<?>) r).get();
            } catch (CancellationException ce) {
                t = ce;
            } catch (ExecutionException ee) {
                t = ee.getCause();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt(); // ignore/reset
            }
        }
        if (t != null) {
            System.out.println(t);
        }
    }
}
于 2013-02-21T09:57:17.587 に答える