Implementieren Sie eine ExecutorService zur Ausführung von batches von Aufgaben
Ich bin auf der Suche nach einer Möglichkeit zur Ausführung von batches von Aufgaben in java. Die Idee ist, eine ExecutorService
basiert auf einem thread-pool, der wird mir erlauben, zu verbreiten, eine Reihe von Callable
zwischen verschiedenen threads von einem main
thread. Diese Klasse sollte eine "waitForCompletion" Methode, die die main
thread schlafen, bis alle Aufgaben ausgeführt werden. Dann die main
thread soll geweckt werden, und es werden einige Operationen durchzuführen und erneut eine Reihe von Aufgaben.
Dieser Prozess wird mehrmals wiederholt, so möchte ich ExecutorService.shutdown
wie dies erforderlich wäre, um mehrere Instanzen von ExecutorService
.
Derzeit habe ich umgesetzt es in der folgenden Weise mit einer AtomicInteger
, und ein Lock
/Condition
:
public class BatchThreadPoolExecutor extends ThreadPoolExecutor {
private final AtomicInteger mActiveCount;
private final Lock mLock;
private final Condition mCondition;
public <C extends Callable<V>, V> Map<C, Future<V>> submitBatch(Collection<C> batch){
...
for(C task : batch){
submit(task);
mActiveCount.incrementAndGet();
}
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
mLock.lock();
if (mActiveCount.decrementAndGet() == 0) {
mCondition.signalAll();
}
mLock.unlock();
}
public void awaitBatchCompletion() throws InterruptedException {
...
//Lock and wait until there is no active task
mLock.lock();
while (mActiveCount.get() > 0) {
try {
mCondition.await();
} catch (InterruptedException e) {
mLock.unlock();
throw e;
}
}
mLock.unlock();
}
}
Bitte nicht, dass ich nicht unbedingt Einreichen, alle Aufgaben aus dem Stapel auf einmal, daher CountDownLatch
scheint nicht eine option sein.
Ist dies ein Gültiger Weg, es zu tun? Gibt es eine effizientere/elegante Art und Weise zu implementieren, dass?
Dank
- Können Sie erklären, ein bisschen mehr, warum die Standard-Vollstrecker kann nicht mit Ihr Anwendungsfall? Warum brauchen Sie, um zu erweitern
ThreadPoolExecutor
? - Auch die API nicht angeben, wird eine Methode zum warten auf die Vollendung aller eingereichten Aufgaben, es sei denn, Sie rufen
shutdown
ersten. In meinem Fall will ich nicht bis zur Abschaltung der Vollstrecker, wie ich, müssen es fast sofort nach, und das würde dazu führen, dass sinnlos-thread-Kreationen. Ist es Antwort auf deine Frage? - Siehe diese Frage: stackoverflow.com/questions/3269445/...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich denke, die ExecutorService selbst in der Lage zu erfüllen Ihre Anforderungen.
Call
invokeAll([...])
und iterieren über alle Ihre Aufgaben. Alle Aufgaben fertig sind, wenn Sie Durchlaufen können alle Futures.main
thread könntebreak
die Ausführung der Schleife), deshalb kann ich nicht verlassen sich aufinvokeAll
. Ich könnte warten auf dieFuture.get
extern, aber ich dachte, es war besser, in Sachen design haben die Testamentsvollstrecker zuständig. Ich kann mich irren aber 😉main
thread könnte ebenso gut unterbrochen werden, während Sie schlafen, sind Sie eigentlich planen es, zu unterbrechen, oder ist das nur entstanden, weilInterruptedException
wird geprüft?invokeAll
intern wartet, bis alle Aufgaben abgeschlossen sind, kann dies die sauberste Lösung, ich werde überarbeiten Sie den code mit der Unterbrechung Haupt-thread (ich spreche nicht von einem AufrufThread.interrupt
nur eine bedingtebeak
in die Schleife, die mit der Erstellung von Aufgaben)Als die anderen Antworten weisen darauf hin, es scheint nicht zu jeder Teil von Ihr Anwendungsfall erfordert eine benutzerdefinierte ExecutorService.
Scheint es mir, dass alle Sie tun müssen, ist senden Sie einen Stapel, warten bis diese fertig sind, während das ignorieren von interrupts auf dem Haupt-thread, dann reichen Sie vielleicht eine andere charge auf der Grundlage der Ergebnisse der ersten charge. Ich glaube, das ist nur eine Frage von:
Stimme ich mit @ckuetbach, dass die Standard-Java -
Executors
sollten Ihnen alle Funktionen, die Sie ausführen müssen, eine "batch" jobs.Wenn ich du wäre würde ich nur senden Sie eine Reihe von jobs, warten, bis Sie fertig sind mit der
ExecutorService.awaitTermination()
und dann einfach starten Sie eine neueExecutorService
. Auf diese Weise sparen "- thread creations" ist die vorzeitige Optimierung, es sei denn, Sie tun dies, 100s von Zeiten eine Sekunde oder so.Wenn Sie wirklich stecken, mit dem gleichen
ExecutorService
für jede der Chargen, dann können Sie reservieren einThreadPoolExecutor
sich selbst, und werden in einer Schleife betrachtenThreadPoolExecutor.getActiveCount()
. So etwas wie:executor.getActiveCount()
API sagt, es ist nur eine Ungefähre Anzahl, und dieThread.sleep
ist nicht eine gute option für mich, da will ich so schnell wie möglich: ich bin der Durchführung einer kombinatorischen Optimierungs-Algorithmus und die beiden performance-Metriken Lösung Qualität und Geschwindigkeit, jede ms zählt!