Advanced Java Services | Executors.newFixedThreadPool() |
Ein FixedThreadPool arbeitet mit einem ThreadPool fester Größe, die nicht mehr veränderbar ist. Bis zu dieser Größe werden Threads erzeugt. Die Anzahl der tatsächlich laufenden Threads bestimmt der ExecutorService selbst. Kann ein Thread nicht gestartet werden, wird er in die Warteschlange zurückgestellt und ein anderer Task wird gestartet.
Das Beispiel erzeugt einen Pool der Größe 3, dem aber 5 Threads übergeben werden. Die Tasks sind Callables und werden in einer Schleife über submit() übergeben.
Die Tasks erledigen ihre Aufgabe in fünf Schritten.
class CTask implements Callable<String> { private int i; public CTask(int i) { this.i = i; } public String call() throws Exception { String name = Thread.currentThread().getName(); for(int j = 0; j < 5; j++) { // Perform some work... System.out.format("%s, c%d, completed: %3d%% %s\n", Thread.currentThread().getName(), i, 20*j, LocalTime.now()); TimeUnit.MILLISECONDS.sleep((int) (Math.random() * 1000)); } System.out.format("%s, c%d, completed: 100%% %s\n\n", Thread.currentThread().getName(), i, LocalTime.now()); return name; } }
Und werden mit submit() übergeben.
private static void startCallablesWithSubmit() { ExecutorService ftp = Executors.newFixedThreadPool(3); // Arrays anlegen CTask[] ctask = new CTask[5]; for(int i=0 ; i < 5; i++) { ctask[i] = new CTask(i); } for(int i=0 ; i < 5; i++) { ftp.submit(ctask[i]); } ftp.shutdown(); }
Eine mögliche Ausgabe
pool-1-thread-3, c2, completed: 0% 15:28:05.471 pool-1-thread-2, c1, completed: 0% 15:28:05.471 pool-1-thread-1, c0, completed: 0% 15:28:05.471 pool-1-thread-3, c2, completed: 20% 15:28:05.879 pool-1-thread-3, c2, completed: 40% 15:28:06.317 pool-1-thread-1, c0, completed: 20% 15:28:06.365 pool-1-thread-2, c1, completed: 20% 15:28:06.431 pool-1-thread-1, c0, completed: 40% 15:28:06.769 pool-1-thread-2, c1, completed: 40% 15:28:06.782 pool-1-thread-3, c2, completed: 60% 15:28:07.288 pool-1-thread-1, c0, completed: 60% 15:28:07.340 pool-1-thread-2, c1, completed: 60% 15:28:07.637 pool-1-thread-1, c0, completed: 80% 15:28:07.896 pool-1-thread-3, c2, completed: 80% 15:28:08.249 pool-1-thread-3, c2, completed: 100% 15:28:08.250 pool-1-thread-3, c3, completed: 0% 15:28:08.250 pool-1-thread-1, c0, completed: 100% 15:28:08.464 pool-1-thread-1, c4, completed: 0% 15:28:08.464 pool-1-thread-2, c1, completed: 80% 15:28:08.513 pool-1-thread-2, c1, completed: 100% 15:28:08.909 pool-1-thread-3, c3, completed: 20% 15:28:09.081 pool-1-thread-1, c4, completed: 20% 15:28:09.289 pool-1-thread-1, c4, completed: 40% 15:28:09.455 pool-1-thread-3, c3, completed: 40% 15:28:09.536 pool-1-thread-1, c4, completed: 60% 15:28:09.791 pool-1-thread-1, c4, completed: 80% 15:28:10.238 pool-1-thread-3, c3, completed: 60% 15:28:10.533 pool-1-thread-1, c4, completed: 100% 15:28:10.874 pool-1-thread-3, c3, completed: 80% 15:28:10.935 pool-1-thread-3, c3, completed: 100% 15:28:11.920
Ein Blick in den Quellcode zeigt, daß der mit newFixedThreadPool() gelieferte ExecutorService ein ThreadPoolExecutor ist und wie der bereits vorgestellte SingleThreadExecutor eine LinkedBlockingQueue verwendet
public static ExecutorService newFixedThreadPool(int nThreads)
{
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
Executors.newFixedThreadPool() liefert einen vollwertigen vorkonfigurierten ThreadPoolExecutor. Er arbeitet mit einer LinkedBlockingQueue<Runnable> und verwendet die DefaultThreadFactory. Man kann also die geliefert Instanz auf den Typ ThreadPoolExecutor casten und erhält damit Zugriff auf die Metrhoden von ThreadPoolExecutor.