java - ライブ - デーモンスレッドとは




JavaでExecutorServiceをデーモンにする (5)

私はJava 1.6でExecutoreServiceを使用しています。

ExecutorService pool = Executors.newFixedThreadPool(THREADS). 

私のメインスレッドが終了すると(スレッドプールによって処理されるすべてのタスクと共に)、このプールは明示的に呼び出すまで私のプログラムがシャットダウンするのを防ぎます

pool.shutdown();

このプールで使用されている内部スレッドをデアモンスレッドに変えて、何とかこれを呼び出す必要はありませんか? または、私はここで何かを逃しています。


GuavaのThreadFactoryBuilderクラスを使用します。

ExecutorService threadPool = Executors.newFixedThreadPool(THREADS, new ThreadFactoryBuilder().setDaemon(true).build());

Guavaをまだ使用していない場合は、 Pshemoの回答の先頭にあるようなThreadFactoryサブクラスを使用します


Marco13の答えにはおそらく最も単純で好ましい解決策がありますので、投票の差(私の答えは数年前です)または合格マークに惑わされないようにしてください(私の解決策はOPの状況に適していません)。

ThreadFactoryを使用してExecutor内のスレッドをデーモンに設定できます。 これはデーモンスレッドとなるようにエグゼキュータサービスに影響を与え、他のデーモン以外のスレッドがなければ停止します。 ここに簡単な例があります:

ExecutorService exec = Executors.newFixedThreadPool(4,
        new ThreadFactory() {
            public Thread newThread(Runnable r) {
                Thread t = Executors.defaultThreadFactory().newThread(r);
                t.setDaemon(true);
                return t;
            }
        });

exec.execute(YourTaskNowWillBeDaemon);

しかし、実行を終了させるエグゼキュータを取得したいと同時に、アプリケーションが完了したときに同時にshutdown()メソッドを自動的に呼び出す場合は、 Guava's MoreExecutors.getExitingExecutorServiceエグゼキュータをラップすることができます。

ExecutorService exec = MoreExecutors.getExitingExecutorService(
        (ThreadPoolExecutor) Executors.newFixedThreadPool(4), 
        100_000, TimeUnit.DAYS//period after which executor will be automatically closed
                             //I assume that 100_000 days is enough to simulate infinity
);
//exec.execute(YourTask);
exec.execute(() -> {
    for (int i = 0; i < 3; i++) {
        System.out.println("daemon");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

はい。

通常のスレッドではなく、デーモンスレッドを作成する独自のThreadFactoryクラスを作成するだけでThreadFactoryます。


タスクのリストが分かっていれば、デーモンスレッドはまったく必要ありません。 すべてのタスクを実行した後、ExecutorServiceでshutdown()を呼び出すだけで済みます。

メインスレッドが完了したら、awaitTermination()メソッドを使用して、送信されたタスクが完了するまでの時間を許可します。現在送信されたタスクが実行され、完了したスレッドプールは制御スレッドを終了します。

for (Runnable task : tasks) {
  threadPool.submit(task);
}
threadPool.shutdown();
/*... do other stuff ...*/
//All done, ready to exit
while (!threadPool.isTerminated()) {
  //this can throw InterruptedException, you'll need to decide how to deal with that.
  threadPool.awaitTermination(1,TimeUnit.SECOND); 
}

私は通常、スレッドをデーモンスレッドとして実行したいので、次のようにユーティリティクラスを追加しました:

import java.util.concurrent.ThreadFactory;

public class DaemonThreadFactory implements ThreadFactory {

    public final static ThreadFactory instance = 
                    new DaemonThreadFactory();

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
}

これにより、 DaemonThreadFactory.instanceExecutorServiceに簡単に渡すことができます。

ExecutorService exec = Executors.newFixedThreadPool(
    4, DaemonThreadFactory.instance
);

またはRunnableからデーモンスレッドを簡単に起動するために使用します。

DaemonThreadFactory.instance.newThread(
    () -> { doSomething(); }
).start();






java-threads