2016-08-10 4 views
5

Ich möchte in der Lage sein, eine Methode mit der @Async Annotation von seiner Zukunft markiert zu stornieren.Spring Abbrechen @ Async Aufgabe

Ich habe eine Spring-Methode mit der @Async Annotation markiert. Diese Methode führt eine Berechnung durch und gibt schließlich ein Ergebnis zurück. Alle Beispiele, die ich gesehen habe, empfehlen die AsyncResult Klasse, um diese Zukunft zurückzugeben.

@Async 
public Future<String> run() { 
    // ... Computation. Minutes pass ... 
    return new AsyncResult<String>("Result"); 
} 

Ich rufe die folgende Methode aus einer anderen Komponente auf die folgende Weise. Zum Beispiel möchte ich diesen Thread sofort abbrechen:

Future<String> future = component.run(); 
future.cancel(true); 

In diesem Fall wird der Thread nie abgebrochen. Dies ist der Fall, wenn man sich die Spring-Implementierung für AsyncResult hier anschaut: https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java#L71, diese Methode macht eigentlich keine einzige Sache. Es gibt einfach false zurück, dass der Thread nicht abgebrochen werden konnte. Das ist mein Problem. Wie kann ich den Thread löschen, der mit der Methode @Async erstellt wurde? Ich habe keinen Zugang zu dem internen Thread, der von Spring erstellt wird - also habe ich keine Mittel, mit denen ich es abbrechen kann, oder?

+0

überprüfen Sie diese 2 Antworten [hier] (http://stackoverflow.com/questions/21084195/spring-async-cancel-and-start) und [hier] (http://stackoverflow.com/questions/35798987/ stop-async-spring-method-from-caller-class), oder erstellen Sie einen benutzerdefinierten 'ThreadPoolExecutor', um die annotierten Methoden '@ Async' zu behandeln oder übergeben Sie ein benutzerdefiniertes' AsyncResult', das an die laufende Aufgabe bindet. – AntJavaDev

+0

Die Antworten in diesen Fragen scheinen die Erstellung eines Flags/Semaphors zu beschreiben, damit der laufende Thread die Verarbeitung zu einem späteren Zeitpunkt stoppen kann. Dies ist anders als das Beenden eines Threads, wie es die Future.cancel() -Methode in einem selbst definierten 'Runnable' machen würde. Können Sie etwas weiter erklären, wie ein benutzerdefinierter 'ThreadPoolExecutor' aussehen würde? Ich definiere auch meinen eigenen Executor, also wäre es nicht schwierig oder unbequem, ihn hinzuzufügen. –

Antwort

4

Tatsächlich verwendet Frühling @Async einen Hintergrundthread-Pool seiner eigenen. Und solange die Methode cancel() von Future oder shutdownNow() des Executor-Dienstes betroffen ist, wird der laufende Thread durch den Aufruf executor.shutdownNow() or future.cancel(true) nicht sofort gestoppt. Was diese Methoden tun, ist einfach .interrupt() auf den jeweiligen Thread (s) zu nennen. Und interrupts hat keine garantierte sofortige Wirkung. Es wird ein Flag ausgegeben, so dass der Thread im Schlaf- oder Wartezustand gestoppt wird. Wenn Ihre Aufgaben die Unterbrechung ignorieren, verhält sich executor.shutdownNow() and future.cancel(true) genauso wie executor.shutdown() and future.cancel(false).

Wenn Sie eine Möglichkeit benötigen, den langsamen oder blockierenden Vorgang zu stoppen. Wenn Sie eine lange/endlose Schleife haben, können Sie einfach eine Bedingung hinzufügen, ob Thread.currentThread().isInterrupted(), und nicht fortfahren, wenn es wahr ist (die Operation beenden).

+0

Großartig. Ich fügte boolesche Überprüfungen für 'Thread.interrupted()' in meiner gesamten '@ Async'-Methode hinzu. und wenn ich den Interrupt erkenne, kann ich die Methode sicher abbrechen und die Ausführung abbrechen. –