88

私はJava1.6でExecutoreServiceを使用しています。

ExecutorService pool = Executors.newFixedThreadPool(THREADS). 

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

pool.shutdown();

このプールで使用される内部スレッド管理をデーモンスレッドに変換することで、これを呼び出す必要を回避できますか?または私はここで何かが欠けていますか?

4

9 に答える 9

114

おそらく最も単純で好ましい解決策はMarco13の回答にあるので、投票の違い(この回答は数年前)や承認マーク(この解決策がOPの状況に適していたことを意味し、一般的には最善ではない)に惑わされないでください。 。


ThreadFactoryExecutor内のスレッドをデーモンに設定するために使用できます。これはエグゼキュータサービスに影響を与え、デーモンスレッドにもなるため、デーモン以外のスレッドが他にない場合は、エグゼキュータサービス(およびそれによって処理されるスレッド)が停止します。簡単な例を次に示します。

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);

ただし、タスクを終了させ、同時にアプリケーションの完了時にそのメソッドを自動的に呼び出すエグゼキュータを取得する場合は、エグゼキュータをGuavashutdown()でラップすることをお勧めします。 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();
        }
    }
});
于 2012-12-14T17:21:22.663 に答える
58

を作成するための組み込み機能がすでにありExecutorService、一定期間非アクティブになった後にすべてのスレッドを終了します。を作成しThreadPoolExecutor、必要なタイミング情報を渡してから、allowCoreThreadTimeout(true)このエグゼキュータサービスを呼び出すことができます。

/**
 * Creates an executor service with a fixed pool size, that will time 
 * out after a certain period of inactivity.
 * 
 * @param poolSize The core- and maximum pool size
 * @param keepAliveTime The keep alive time
 * @param timeUnit The time unit
 * @return The executor service
 */
public static ExecutorService createFixedTimeoutExecutorService(
    int poolSize, long keepAliveTime, TimeUnit timeUnit)
{
    ThreadPoolExecutor e = 
        new ThreadPoolExecutor(poolSize, poolSize,
            keepAliveTime, timeUnit, new LinkedBlockingQueue<Runnable>());
    e.allowCoreThreadTimeOut(true);
    return e;
}

編集コメント内のコメントを参照してください。このスレッドプールエグゼキュータは、アプリケーションの終了時に自動的にシャットダウンされないことに注意してください。エグゼキュータは、アプリケーションが終了した後も実行を継続しますが、それより長くはなりませんkeepAliveTime。正確なアプリケーション要件に応じて、keepAliveTimeが数秒より長くなければならない場合は、 Pshemoによる回答の解決策がより適切な場合があります。スレッドがデーモンスレッドに設定されている場合、アプリケーションが終了するとすぐに終了します。 。

于 2015-04-05T01:19:32.943 に答える
23

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

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

まだGuavaを使用していない場合は、Pshemoの回答の上部に記載されているようなThreadFactoryサブクラスを使用します。

于 2015-04-08T16:35:06.230 に答える
10

1つの場所でのみ使用する場合は、java.util.concurrent.ThreadFactory実装をインライン化できます。たとえば、4つのスレッドを含むプールの場合(Java 1.8以降を想定したラムダとして示されている例):

ExecutorService pool = Executors.newFixedThreadPool(4,
        (Runnable r) -> {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
);

しかし、私は通常、すべてのスレッドファクトリでデーモンスレッドを生成する必要があるため、次のようにユーティリティクラスを追加します。

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 pool = Executors.newFixedThreadPool(
    4, DaemonThreadFactory.instance
);

または、これを使用して、からデーモンスレッドを簡単に開始します。Runnable

DaemonThreadFactory.instance.newThread(
    () -> { doSomething(); }
).start();
于 2018-08-19T22:22:23.937 に答える
5

はい。

ThreadFactory通常のスレッドではなくデーモンスレッドを作成する独自のクラスを作成する必要があります。

于 2012-12-14T17:14:42.207 に答える
0

このソリューションは@Marco13のソリューションに似ていますが、独自のソリューションを作成する代わりに、ThreadPoolExecutorによって返されるソリューションを変更できExecutors#newFixedThreadPool(int nThreads)ます。方法は次のとおりです。

ExecutorService ex = Executors.newFixedThreadPool(nThreads);
 if(ex instanceof ThreadPoolExecutor){
    ThreadPoolExecutor tp = (ThreadPoolExecutor) ex;
    tp.setKeepAliveTime(time, timeUnit);
    tp.allowCoreThreadTimeOut(true);
}
于 2018-09-09T18:17:05.983 に答える
0

GuavaのThreadFactoryBuilderを使用できます。依存関係を追加したくなく、Executors.DefaultThreadFactoryの機能が必要だったので、compositionを使用しました。

class DaemonThreadFactory implements ThreadFactory {
    final ThreadFactory delegate;

    DaemonThreadFactory() {
        this(Executors.defaultThreadFactory());
    }

    DaemonThreadFactory(ThreadFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = delegate.newThread(r);
        thread.setDaemon(true);
        return thread;
    }
}
于 2019-07-04T20:39:29.690 に答える
0

これは、手元にある質問に正確に答えるわけではありませんが、役立つ場合があります。

他の人がコメントしているように、インラインまたはユーティリティクラスとしてDaemonThreadFactoryを作成できます。

Runnableをサブクラス化することにより、上記のファクトリから結果のDaemonThreadを取得して、個別に生成された非デーモンスレッド内で実行可能ユニット全体を実行できます。通常の状況では、エグゼキュータで使用されるデーモンスレッドが閉じられるように指定されていても、この非デーモンスレッドは完了します。

ここに小さな例があります:

import static java.util.concurrent.TimeUnit.*;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;

public class ScheduleStackOverflow {

    private static final DateTimeFormatter DTF_HH_MM_SS = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");

    private static final class ThreadRunnable implements Runnable {

        private final Runnable runnable;

        public ThreadRunnable(final Runnable runnable) {
            this.runnable = runnable;
        }
        @Override
        public void run() {
            final Thread delegateThread = new Thread(this.runnable);
            /**/         delegateThread.setDaemon(false); // TODO Try changing this to "true"
            /**/         delegateThread.start();
        }
    }

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

        final     ThreadFactory daemonThreadFactory = (daemonRunnable) -> {
            final Thread        daemon = new Thread   (daemonRunnable);
            /**/                daemon.setDaemon(true);
            return              daemon;
        };

        final Runnable runnable = new ThreadRunnable(() -> {
            System.out.println(DTF_HH_MM_SS.format(LocalTime.now()) + " daemon=" + Thread.currentThread().isDaemon() + " Scheduling...");

            sleep(5, SECONDS);

            System.out.println(DTF_HH_MM_SS.format(LocalTime.now()) + " daemon=" + Thread.currentThread().isDaemon() + " Schedule done.");
        });

        Executors
        .newSingleThreadScheduledExecutor(daemonThreadFactory)
        .scheduleAtFixedRate(runnable, 0, Duration.ofSeconds(10).toNanos(), NANOSECONDS);

        sleep(12, SECONDS);

        System.out.println(DTF_HH_MM_SS.format(LocalTime.now()) + " Main CLOSED!");
    }

    private static void sleep(final long timeout, final TimeUnit timeunit) {
        try {timeunit.sleep(timeout);} catch (InterruptedException e) {}
    }
}
于 2021-03-21T11:08:03.900 に答える
-1

既知のタスクのリストがある場合は、デーモンスレッドはまったく必要ありません。すべてのタスクを送信した後、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); 
}
于 2015-04-08T17:36:05.020 に答える