web-dev-qa-db-ja.com

実行時間の長いスレッドにExecutorServiceを使用する理由

プロセスの存続期間中実行し続けるデーモンスレッドを生成するオブジェクトが必要です。議論のために、それは組み込みシステムのスレッドであり、いくつかの診断ポートでコマンドを受信して​​処理するのを待機しているとしましょう。しかし、実際には何でもかまいません。主なアイデアは、長期間にわたって何かを監視することです。 タスクのシーケンスを実行していません。

共通Java知恵は言う、決してインスタンス化しないThread、代わりにExecutorServiceを使用してください。(たとえば、 この答え)を参照してください )しかし、メリットは?スレッドpoolを単一の長期実行スレッドを作成する手段として使用するのは無意味に思われます。

class Foobar {
    public Foobar() {
        this.threadFactory = Executors.defaultThreadFactory();
        ...
    }

    public Foobar(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        ...
    }

    public void start() {
        fooThread = threadFactory.newThread(new Runnable() { ... });
        fooThread.setDaemon(true);
        fooThread.start();
    }
    ...
}

注: この質問 は私のものに似ているようですが、答えはhowとだけ言ってなぜ

8
Solomon Slow

「ネバー」は言葉が強すぎると思います。それは、最適化の2番目のルールである「(まだ)しない」に似ています。

私の意見では、executorサービスを使用する主な理由は、実行中のスレッドの数を管理することです。任意のクラスが独自のスレッドを作成できるようにすると、1,000のCPUバウンド(または常にコンテキスト切り替え)のスレッドがすぐに見つかる場合があります。 executorサービスは、スレッドの作成に制約を設けることにより、この問題を解決します。

副次的な理由は、スレッドを開始するには適切にを考える必要があるためです。

  • デーモンか非デーモンか?これを誤解すると、System.exit()を呼び出してプログラムをシャットダウンする必要があります。
  • 何を優先しますか?多くのSwingプログラマーは、CPU集中型のタスクを処理するためにバックグラウンドスレッドをスピンアップすることで賢いと思っていましたが、イベントディスパッチスレッドが最高の優先度で実行され、子スレッドが親の優先度を継承することを理解していませんでした。
  • キャッチされない例外に対処する方法は?
  • 適切な名前は何ですか?名前にこだわるのはばかげているように見えますが、目的に応じた名前のスレッドはデバッグに多くの助けを与えます。

とはいえ、スレッドプールに依存するのではなく、スレッドを起動する方が適切な場合もあります。

  • 私のアプリケーションがタスクを生成しているで、それらのタスクの実行方法を制御したい場合は、スレッドプールを使用します。
  • 1つまたはいくつかのスレッドがexternally-generatedイベントの処理専用である専用スレッドを作成します。

「外部生成」はコンテキストに依存します。古典的なケースは、メッセージキューまたはソケットの最後にあるスレッドで、そのキューをポーリングし、いくつかのアクション(タスクをプールにディスパッチすることを含む)を実行する必要があります。

ただし、特定のモジュールの外部で生成されたイベントを参照することもできます。たとえば、アプリケーションがプールを提供することを期待するのではなく、Log4JのAsyncAppenderが独自のスレッドを起動することは完全に妥当だと思います。

11
kdgregory