In Zeiten, in denen sogar Smartphones mit Octa-Core-Prozessoren ausgestattet sind, ist es normalerweise üblich, die App an die Vielzahl der von der Hardware bereitgestellten Ressourcen anzupassen. Nahezu alle modernen Apps sind optimiert, um die Nutzung dieser Eigenschaften zu maximieren. Ein Thread Pool ist das Software-Entwurfsmuster, um die Parallelität in Computerprogrammen zu erreichen.

 

Aufgrund der Tatsache, dass für solche Operationen viele Ressourcen erforderlich sind, sowohl Arbeitsspeicher als auch Prozessor-Nutzung, ist es eine gute Praxis bei der Erstellung der App, dass der Programmierer die Threads nicht selbst erstellt und zerstört. Außerdem muss der Programmierer in dieser Situation daran denken, alle Notfallsituationen zu bedienen.

In einer 64-Bit-Umgebung belegt jeder Thread beim Start standardmäßig 1 MB Arbeitsspeicher. Wie Sie sich vorstellen können – das Erstellen neuer Threads ohne strikte Kontrolle – kann die App schnell den gesamten verfügbaren Speicher allokieren. Ein klassisches Beispiel für ein Antimuster in diesem Bereich ist das Erstellen eines neuen Threads für jede Anforderung in einer Webanwendung – diese Lösung wird unserer App ein Ende setzen.

Java bietet ab Version 1.5 eine Executors-Factory mit statischen Methoden zum Erstellen von Thread Pools. Um einen neuen Thread zu erstellen, können Sie die newSingleThreadExecutor-Methode verwenden, indem Sie einfach die Methode aufrufen:

Executors.newSingleThreadExecutor()

Wenn Sie den Pool von Threads mit einer bestimmten Anzahl von Threads verwenden müssen, hilft Ihnen die newFixedThreadPool-Methode, deren Verwendung ebenso einfach ist:

Executors.newFixedThreadPool(int numberOfThreads)

Wobei als Parameter die Anzahl der Threads angenommen wird. Threads in einem solchen Pool werden wiederverwendet.

Wenn Sie eine Aufgabe mit Verzögerung ausführen wollen, verwenden Sie die Methode:

Executors.newCachedThreadPool()

zum Beispiel:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(60); 

ScheduledFuture<String> scheduledFuture = scheduledExecutorService.schedule(task, 60, TimeUnit.SECONDS); 

scheduledFuture.get();

wobei Sie im Parameter die Anzahl der benötigten Threads angeben.

In einem bestimmten Fall benötigen Sie jedoch einen Pool, der nicht über eine bestimmte Anzahl von Threads verfügt. Mit Hilfe von newCachedThreadPool können Sie Ihren Bedarf realisieren. Dieser Pool, wenn er neue Threads benötigt – erstellt diese. Wenn der Thread fertig ist, kann er wieder verwendet werden, sofern er etwas zu tun hat. In dieser Poolimplementierung werden alle Threads, die mindestens eine Minute lang inaktiv sind, daraus entfernt. Dieser Pool funktioniert gut, wenn Sie kurze Aufgaben erledigen müssen. Sie können ihn verwenden, indem Sie die Methode aufrufen:

Executors.newCachedThreadPool()

Sie können auch den Work Stealing-Algorithmus verwenden:

Executors.newWorkStealingPool()

Dieser Algorithmus basiert auf der Tatsache, dass die nicht arbeitenden Threads die Arbeit anderer Threads “stehlen”. Der Algorithmus teilt Aufgaben in kleinere Unteraufgaben auf und platziert sie in der Warteschlange. Die Unteraufgaben werden in verschiedenen Threads ausgeführt, während diejenigen, die ihre Arbeit beendet haben, sie von anderen stehlen. Die Implementierung dieser Art von Pool in Java ist ForkJoinPool.

Verwenden Sie diesen Pool, wenn Sie Aufgaben ausführen müssen, die Sie leicht in kleinere aufteilen können.

Weitere Informationen zu Executors und ExecutorService finden Sie in der offiziellen Java-Dokumentation:

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html