Advanced   Java   Services Executors.newFixedThreadPool()


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.


Beispiel

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

Welcher ExecutorService wird geliefert

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>()));
}

Zusammenfassung

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.