Was ist ein ExecutorService?

Um ehrlich zu sein, ist diese Frage nicht zu neu. Mehr als 13 Jahre sind seit der Veröffentlichung von Java 5 und java.util.concurrent vergangen. * Paket, aber in all meinen zehn Jahren der Praxis musste ich mich diesem Biest nie stellen. Trotzdem wurde mir diese Frage während der Interviews mehrmals gestellt und ich musste mich kennenlernen.



Das erste, mit dem ich angefangen habe, ist natürlich Habr. Leider habe ich hier nur zwei Artikel gefunden:



habrahabr.ru/post/260953

habrahabr.ru/post/116363



Der erste natürlich für diejenigen, die ExecutorService verstehen und Erfahrung damit haben. Der zweite hat mich leider nicht betreten. Es scheint klein und "auf dem Fall", aber nach mehrmaligem Nachlesen verstehe ich immer noch nicht, was ExecutorService ist und womit es gegessen wird. Also musste ich mich zu Eclipse setzen, rauchen, Javadoc lesen und es herausfinden.



Schauen wir uns also ein einfaches Beispiel an:



ExecutorService service = Executors.newFixedThreadPool(3);
service.execute(new Runnable() {
    public void run() {
        System.out.println("Another thread was executed");
    }
});

      
      





In diesem Beispiel haben wir das ExecutorService-Objekt selbst erstellt und die execute-Methode darauf aufgerufen. Übergabe der am häufigsten verwendeten Thread-Implementierung. All dies hätte auf die Weise des alten Großvaters gebaut werden können, aber das ist viel einfacher und eleganter. Tatsächlich haben wir schnell einen anderen asynchronen Thread vom aktuellen Thread abgezweigt, der dort im Hintergrund etwas tun kann.

Wir haben das ExecutorService-Objekt mithilfe einer Factory erstellt. Seine Methoden sind ziemlich offensichtlich, so dass wir nicht zu zögern werden. Hier sind einige davon:



ExecutorService service1 = Executors.newSingleThreadExecutor();
ExecutorService service2 = Executors.newFixedThreadPool(3);
ExecutorService service3 = Executors.newScheduledThreadPool(3);

      
      





Neben der Execute-Methode, die nach dem "Fire and Forget" -Prinzip aufgerufen wird, verfügt unser Service auch über eine Submit-Methode. Der einzige Unterschied zu ersteren besteht darin, dass letztere ein Objekt der Future-Schnittstelle zurückgeben. Dies ist nur eine großartige Möglichkeit, den Status des Threads zu steuern, den wir im Hintergrund ausführen. Es wird ungefähr so ​​gemacht:



Future future = service.submit(new Runnable() {
    public void run() {
        System.out.println("Another thread was executed");
    }
});
...
future.get();

      
      





Beachten Sie, dass die get-Methode den aktuellen Thread tödlich blockiert und wartet, bis der Hintergrund-Thread beendet ist. Jetzt brauchen Sie nicht alle diese nicht offensichtlichen Verknüpfungen! Wenn wir befürchten, dass unser Hintergrund-Thread niemals beendet wird, können wir get (long, TimeUnit) verwenden.



Manchmal müssen Sie Daten von einem Hintergrundthread zum aktuellen zurückgeben. Die Submit-Methode hilft uns auch dabei, aber jetzt müssen wir kein Runnable-Objekt, sondern ein Callable-Objekt an sie übergeben. Tatsächlich sind dies zwei identische Schnittstellen. Der einzige Unterschied besteht darin, dass letztere etwas zurückgeben können:



Future future = service.submit(new Callable(){
    public Object call() throws Exception {
        System.out.println("Another thread was executed");
        return "result";
    }
});
...
System.out.println("Result: " + future.get());

      
      





Kurz gesagt, das ist alles. Waren Methoden zum Erstellen von ExecutorService - und in der Factory (die es viele gibt), waren die Methoden des ExecutorService, Fehlerbehandlungsprobleme in einem Hintergrund-Thread, aber das ist eine andere Geschichte ...



Am Ende vergessen Sie nicht:



servcie.shutdown();

      
      





Oder nicht, wenn alle Hintergrund-Threads Dämonen sind.



All Articles