2017-04-21 2 views
0

Ich habe eine Methode producer.postMessage (Nachricht), die eine Nachricht an eine Warteschlange sendet. Wenn die Nachricht aus irgendeinem Grund nicht innerhalb eines bestimmten Zeitraums gesendet werden konnte, muss diese Aufgabe abgebrochen werden. Ich habe die folgende Implementierung entwickelt. Meine Frage ist, ob es einen Interrupt gibt, kann ich sicher sein, dass der Future-Task/Executor-Dienst alle heruntergefahren wird und wenn nicht, welche Änderungen vorgenommen werden müssen, damit dies funktioniert, ohne dass irgendwelche Threads beendet werden.Wie sicher sein, Threads sind bereinigt

Vielen Dank

public void postMessage(final Object object) 
{ 
    LOG.debug("postMessage object " + object.getClass().getSimpleName()); 

    Message message = new Message("task", 10, object); 

    try 
    { 
     ExecutorService ex = Executors.newSingleThreadExecutor(); 
     Future<?> f = ex.submit(new Runnable() 
     { 
      public void run() 
      { 
       producer.postMessage(message); 
       LOG.debug("Finished sending message for " + object.getClass().getSimpleName()); 
      } 
     }); 
     f.get(5, TimeUnit.SECONDS); 
     ex.shutdown(); 
    } 
    catch (InterruptedException | ExecutionException | TimeoutException e) 
    { 
     LOG.error("Could not deliver message to the queue, Check AMQ is running"); 
    } 
} 
+0

warum nicht verwenden 'shutdownNow' statt' shutdown' Methode? Auch die 'isTerminated'-Methode kann verwendet werden, um die erfolgreiche Beendigung aller Aufgaben zu überprüfen. –

Antwort

0

Die shutdown() Methode auf einem Executor es von der Annahme neue Aufgaben zu stoppen, sondern versucht, die laufenden Aufgaben zu erledigen. Sie sollten die Methode shutdownNow() verwenden, damit der Executor anfordert, dass derzeit ausgeführte Aufgaben gestoppt werden.

Dies ist jedoch möglicherweise nicht erforderlich, wenn Sie die Methode cancel(boolean mayInterruptIfRunning) für das Future-Objekt verwenden. f.get(5, TimeUnit.SECONDS) wartet maximal 5 Sekunden auf die Beendigung der Aufgaben vor der Rückkehr. Da Sie eine Runnable anstelle einer Callable senden, wird die Rückgabe immer Null sein; Runnables können kein Ergebnis zurückgeben, Callables hingegen können. Was Sie tun können, ist isDone() auf die Zukunft nach dem get mit einem Timeout von 5 Sekunden aufrufen, und wenn es false zurückgibt, bedeutet dies, dass die Aufgaben nicht abgeschlossen ist. In diesem Fall können Sie dann cancel(true) in der Zukunft anrufen, um zu versuchen, die Aufgabe abzubrechen. Das wahre Argument zeigt an, dass Sie es der Zukunft erlauben, den Thread zu unterbrechen, wenn er ausgeführt wird. Sie möchten möglicherweise InterruptedExceptions in Ihrem Runnable abfangen und sie protokollieren. Beachten Sie jedoch, dass nicht jeder Aufruf auf Interrupt-Anforderungen reagieren kann (z. B. einige E/A-Operationen möglicherweise nicht, während eine Menge Java NIO-Zeug).

Das Herunterfahren auf dem Executor ist möglicherweise nicht mehr notwendig, da es nur für eine einzelne Task verwendet wird und keine anderen wartenden oder laufenden Tasks haben sollte, aber es ist wahrscheinlich immer noch eine gute Form.

So würde Ihr Code werden:

f.get(5, TimeUnit.SECONDS); 
if (!f.isDone()) 
    f.cancel(true); 
ex.shutdown();