Java Testamentsvollstrecker: Wie kann ich eingereichten Aufgaben stoppen?
-
07-07-2019 - |
Frage
Ich habe eine Aufgabe mit Vollstreckern vorgelegt und ich brauche es nach einiger Zeit zu stoppen (zum Beispiel 5 Minuten). Ich habe versucht, wie dies zu tun:
for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
try {
fut.get();
} catch (CancellationException ex) {
fut.cancel(true);
tasks.clear();
} catch(ExecutionException ex){
ex.printStackTrace(); //FIXME: gestita con printstack
}
}
Aber ich immer einen Fehler: Ich habe ein Foto geteilt, die von den Aufgaben geändert werden muss und dann von einem Thread gelesen, und selbst wenn ich aufhören alle die Aufgabe, wenn das Timeout auftritt, erhalte ich:
Exception in thread "Thread-1" java.util.ConcurrentModificationException
Gibt es etwas falsch? Wie kann ich die Aufgaben abgegeben stoppen, die noch nach 5 Minuten arbeiten?
Lösung
Nur weil Sie cancel()
auf Future
nennen, bedeutet nicht, dass die Aufgabe automatisch gestoppt. Sie haben einige Arbeit in der Aufgabe zu tun, um sicherzustellen, dass es zu stoppen:
- Verwenden Sie
cancel(true)
so dass eine Unterbrechung der Aufgabe gesendet wird. - Handle
InterruptedException
. Wenn eine Funktion in Ihrer Aufgabe eineInterruptedException
wirft, stellen Sie sicher, dass Sie anmutig so schnell wie möglich verlassen, auf die Ausnahme zu kontrollieren. - Überprüfen Sie regelmäßig
Thread.currentThread().isInterrupted()
, wenn die Aufgabe kontinuierliche Berechnung der Fall ist.
Zum Beispiel:
class LongTask implements Callable<Double> {
public Double call() {
// Sleep for a while; handle InterruptedException appropriately
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
System.out.println("Exiting gracefully!");
return null;
}
// Compute for a while; check Thread.isInterrupted() periodically
double sum = 0.0;
for (long i = 0; i < 10000000; i++) {
sum += 10.0
if (Thread.currentThread().isInterrupted()) {
System.out.println("Exiting gracefully");
return null;
}
}
return sum;
}
}
Auch, wie andere Beiträge erwähnt haben: ConcurrentModificationException
können sogar geworfen werden, wenn die Thread-sichere Vector
-Klasse, weil Iteratoren Sie von Vector
erhalten sind nicht Thread-sicher und damit synchronisiert werden müssen. Die erweiterte for-Schleife verwendet Iteratoren, also aufgepasst:
final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);
// Not thread safe! If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
System.out.println(num);
}
// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) { // "vector" must be final
for (Double num : vector) {
System.out.println(num);
}
}
Andere Tipps
Die ConcurrentModificationException
von Ihrem Anruf kommen nach tasks.clear()
während Exceutors über Ihre tasks
Vector
iteriert. Was Sie versuchen können, ist Aufruf zu tun shutdownNow()
auf Ihrem ExecutorService
Der häufigste Fall für ConcurrentModificationException
ist, wenn der vector
zugleich geändert wird, wie es wiederholt wird. Oft wird dies in einem einzigen Thread ausgeführt werden. Sie müssen eine Sperre für die Vector
für die gesamte Iteration halten (und vorsichtig, nicht Deadlock).
fut.get () ist ein blockierender Aufruf, auch nach dem Timeout, werden Sie blockieren, bis die Aufgabe erledigt ist. Wenn Sie so nahe an der 5-Minuten-Marke wie möglich stoppen wollen, müssen Sie das Interrupt-Flag überprüfen, empfehle ich nur tun Sie so die Thread.isInterrupted () Methode verwendet, die den Interrupt Zustand bewahrt. Wenn Sie nur wollen sofort stoppen und benötigen keinen Zustand zu reinigen, dann eine Ausnahme aus, die von der Zukunft gefangen werden und angegeben als ExecutionException zu Ihnen.
fut.cancel (true) tut nichts als invokeAll () -Methode dies bereits für Sie getan hat.
Wenn Sie nicht die „Aufgaben“ Collection woanders verwenden, werden Sie wahrscheinlich brauchen, um auf sie nicht nennen clear (). Dies ist nicht die Ursache des Problems sein würde, da die invokeAll () Methode mit der List von der Zeit gemacht wird Ihnen klar () aufrufen. Aber, wenn Sie eine Liste der neuen Aufgaben beginnen müssen Bildung auszuführen, empfehle ich Ihnen eine neue Liste der Aufgaben bilden, nicht eine alte Liste der neuen Aufgaben verwenden.
Leider habe ich keine Antwort für Ihr Problem. Ich sehe nicht genug Informationen hier, um es zu diagnostizieren. Nichts in der Code-Schnipsel Ihnen zur Verfügung gestellten weisen auf eine falsche (nur unnötig) Verwendung von Bibliotheksklassen / Methoden. Vielleicht, wenn Sie einen vollständigen Stack-Trace enthalten, anstelle des einen Leitungsfehler.
Setzen Sie den fut.cancel(true);
in der finally-Block