Ich verwende einen ExecutoreService in Java 1.6, der einfach von gestartet wurde
ExecutorService pool = Executors.newFixedThreadPool(THREADS).
Wenn mein Hauptthread fertig ist (zusammen mit allen vom Thread-Pool verarbeiteten Aufgaben), verhindert dieser Pool, dass mein Programm heruntergefahren wird, bis ich explizit aufrufe
pool.shutdown();
Kann ich vermeiden, dass ich dies aufrufen muss, indem ich die von diesem Pool verwendete interne Thread-Verwaltung irgendwie in einen Deamon-Thread verwandle? Oder fehlt mir hier etwas?
keepAliveTime
je nach Häufigkeit der Ausführung von Aufgaben angemessen sein kann .Antworten:
Die wahrscheinlich einfachste und bevorzugte Lösung ist in der Antwort von Marco13 enthalten. Lassen Sie sich also nicht von Stimmenunterschieden (meine Antwort ist einige Jahre älter) oder Akzeptanzzeichen (es bedeutet nur, dass meine Lösung für OP-Umstände geeignet war, nicht dass sie die beste ist) täuschen.
Sie können
ThreadFactory
Threads in Executor auf Daemons setzen. Dies wirkt sich auf den Executor-Service so aus, dass er auch zum Daemon-Thread wird, sodass er (und die von ihm verarbeiteten Threads) gestoppt werden, wenn kein anderer Nicht-Daemon-Thread vorhanden ist. Hier ist ein einfaches Beispiel: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);
Wenn Sie jedoch einen Executor erhalten möchten, der seine Aufgabe beendet und gleichzeitig seine
shutdown()
Methode automatisch aufruft , wenn die Anwendung abgeschlossen ist, möchten Sie Ihren Executor möglicherweise mit Guavas umschließenMoreExecutors.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(); } } });
quelle
Es gibt bereits eine integrierte Funktion zum Erstellen einer
ExecutorService
, die alle Threads nach einer bestimmten Zeit der Inaktivität beendet: Sie können eine erstellenThreadPoolExecutor
, die gewünschten Zeitinformationen übergeben und dannallowCoreThreadTimeout(true)
diesen Executor-Service aufrufen :/** * 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; }
quelle
shutdown
Methode. Ich habe das ein wenig umformuliert, hoffentlich ist es jetzt weniger zweideutig.main()
Methode beendet. Nachdem die Aufgabe erledigt ist, lebt ExecutorService für keepAliveTime und wartet, bis alle Kernthreads sterben. Das heißt, wenn Sie versuchen, Ihre Java-App ordnungsgemäß zu stoppen, müssen Sie einige (möglicherweise große) Zeit warten. Ich finde es nicht gut. @Pshemo Ich glaube, deine Antwort ist derzeit die beste.keepAliveTime
paar Sekunden (und kann mir zugegebenermaßen kaum vorstellen, wann eine Zeit von mehr als ein paar Sekunden angemessen oder sogar notwendig wäre). Wenn es erforderlich ist, einen größeren zu habenkeepAliveTime
und dennoch sofort zu beenden, ist die Daemon-Thread-Lösung vorzuziehen.ExecutorService
mitallowCoreThreadTimeOut(true)
undkeepAliveTime
klein genug verwenden kann, um es mehr oder weniger schnell sterben zu lassen. Was ist der Vorteil von solchenExecutorService
? Nach einer kurzen Zeit der Inaktivität sterben alle Kernthreads ab, und das Senden einer neuen Aufgabe führt zu einer neuen Thread-Erstellung mit all ihrem Overhead, sodass meine Aufgabe nicht sofort gestartet wird. Es wird kein Pool mehr sein.Ich würde Guavas ThreadFactoryBuilder-Klasse verwenden.
ExecutorService threadPool = Executors.newFixedThreadPool(THREADS, new ThreadFactoryBuilder().setDaemon(true).build());
Wenn Sie Guava noch nicht verwenden, würde ich eine ThreadFactory-Unterklasse verwenden, wie oben in Pshemos Antwort beschrieben
quelle
Wenn Sie es nur an einer Stelle verwenden möchten, können Sie die
java.util.concurrent.ThreadFactory
Implementierung einbinden, z. B. für einen Pool mit 4 Threads, die Sie schreiben würden (Beispiel als Lambda unter der Annahme von Java 1.8 oder neuer):ExecutorService pool = Executors.newFixedThreadPool(4, (Runnable r) -> { Thread t = new Thread(r); t.setDaemon(true); return t; } );
Normalerweise möchte ich jedoch, dass alle meine Thread-Fabriken Daemon-Threads erzeugen. Daher füge ich eine Dienstprogrammklasse wie folgt hinzu:
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; } }
Das erlaubt mir leicht,
DaemonThreadFactory.instance
zumExecutorService
zExecutorService pool = Executors.newFixedThreadPool( 4, DaemonThreadFactory.instance );
oder verwenden Sie es, um einen Daemon- Thread einfach von einem zu starten
Runnable
, zquelle
Ja.
Sie müssen lediglich eine eigene
ThreadFactory
Klasse erstellen , die Daemon-Threads anstelle von regulären Threads erstellt.quelle
Diese Lösung ähnelt der von @ Marco13, aber anstatt unsere eigene zu erstellen
ThreadPoolExecutor
, können wir die von zurückgegebene Lösung ändernExecutors#newFixedThreadPool(int nThreads)
. Hier ist wie:ExecutorService ex = Executors.newFixedThreadPool(nThreads); if(ex instanceof ThreadPoolExecutor){ ThreadPoolExecutor tp = (ThreadPoolExecutor) ex; tp.setKeepAliveTime(time, timeUnit); tp.allowCoreThreadTimeOut(true); }
quelle
newFixedThreadPool
wirdThreadPoolExecutor
. (Es tut und wird es mit ziemlicher Sicherheit für immer tun, aber das wissen Sie nicht )Sie können den ThreadFactoryBuilder von Guava verwenden. Ich wollte die Abhängigkeit nicht hinzufügen und ich wollte die Funktionalität von Executors.DefaultThreadFactory, also habe ich Komposition verwendet:
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; } }
quelle
Wenn Sie eine bekannte Liste von Aufgaben haben, benötigen Sie überhaupt keine Daemon-Threads. Sie können einfach shutdown () im ExecutorService aufrufen, nachdem Sie alle Ihre Aufgaben gesendet haben.
Wenn Ihr Hauptthread abgeschlossen ist, verwenden Sie die Methode awaitTermination (), um Zeit für die Ausführung der übermittelten Aufgaben zu lassen. Die aktuell übermittelten Aufgaben werden ausgeführt, und der Thread-Pool beendet seinen Steuer-Thread, sobald sie abgeschlossen sind.
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); }
quelle