Executor, ExecutorService, Executor – 1

„Hallo, Amigo!“

„Nichts ist perfekt, wenn es zum ersten Mal erstellt wird. Das Gleiche gilt für Threads. Mit der Zeit wurden die Entwickler von Java von den Mängeln der Runnable-Schnittstelle überzeugt. Sie unterstützte das Auslösen von Ausnahmen nicht und machte es nicht möglich, das herauszufinden.“ Ergebnis der Ausführung von Aufgaben…“

„Die Runnable-Schnittstelle eignet sich eher für große unabhängige Aufgaben als für kleine Unteraufgaben, bei denen man ein Dutzend gleichzeitig ausführen und dann deren Ergebnisse sammeln möchte.“

„Deshalb wurde die Callable- Schnittstelle erfunden. Sie eignet sich viel besser für die parallele Ausführung kleiner Aufgaben als Runnable und Thread, auch weil es eine generische Schnittstelle ist.“

„Hier ist eine typische Implementierung der Schnittstelle:“

Beispiel
class ReverseString implements Callable<String>
{
 String str;

 ReverseString(String str)
 {
  this.str = str;
 }

 public String call() throws Exception
 {
  StringBuilder builder = new StringBuilder(str);
  builder.reverse();
  return builder.toString();
 }
}

„Im Gegensatz zu Runnable müssen wir hier die Call-Methode überschreiben, die ein Ergebnis des durch das Typargument angegebenen Typs zurückgibt. Dieser Ansatz ist viel praktischer als die Run-Methode der Runnable-Schnittstelle, die void zurückgibt. Manchmal mussten sich Entwickler etwas einfallen lassen verschiedene Problemumgehungen, um das Ergebnis eines Threads zu erhalten.

"Ich verstehe."

„Und jetzt schauen Sie sich an, wie Callable mit ThreadPoolExecutor zusammenarbeiten kann:

„Zuerst gibt die Submit-Methode der ThreadPoolExecutor -Klasse ein parametrisiertes Future-Objekt zurück. Mit diesem Objekt können Sie herausfinden, ob eine Aufgabe abgeschlossen ist, und das Ergebnis abrufen.“

"So funktioniert das:"

Beispiel
// 1. Create a ThreadPoolExecutor
ExecutorService service = Executors.newFixedThreadPool(5);

// 2. Add a task to it
Future<String> task = service.submit(new ReverseString("Amigo"));

// 3. Wait until the task is done
while(!task.isDone())
{
 Thread.sleep(1);
}

// 4. Try to get the result
//We will get either the result, or an exception if one occurred while the task was being executed
try
{
 System.out.println("Full string : " + task.get());
}
catch (Exception ie)
{
 ie.printStackTrace(System.err);
}
  
// 5. Stop the ThreadPool.
service.shutdown();

„Weit weg! Mir gefällt besonders die Future-Klasse. Welche Methoden hat sie?“

„Hier sind die interessantesten:“

Methode Beschreibung
boolean cancel(boolean mayInterrupt);
Stoppt die Aufgabe.
boolean isCancelled();
Gibt true zurück, wenn die Aufgabe gestoppt wurde.
boolean isDone();
Gibt true zurück, wenn die Ausführung der Aufgabe abgeschlossen ist.
V get() throws InterruptedException, ExecutionException;
Gibt das Ergebnis der Aufrufmethode zurück oder löst eine Ausnahme aus, falls eine solche aufgetreten ist.

„Cool! So kann man Aufgaben auch stoppen.“

„Verlassen Sie sich nicht zu sehr darauf – nicht jeder Thread kann gestoppt werden. Wenn sich jedoch noch eine Aufgabe in der Warteschlange befindet, funktioniert dies einwandfrei.“

„Dieser Ansatz gefällt mir. Er ist viel praktischer, als selbst Threads zu erstellen und dann zu versuchen, daraus ein Ergebnis zu ziehen.“

„Großartig. Damit enden wir heute.“