2009-02-28

ScheduledThreadPoolExecutor : gotcha

This code
final int period = 1000 /*millis*/;
final int delay = 10 /*millis*/;
final int num = 20;

ScheduledExecutorService ses = 
    Executors.newScheduledThreadPool(4);

for (int i = 0; i < num; i++) {
  ses.scheduleWithFixedDelay(

    new Runnable() {
      public void run() {
        try {
          Thread.sleep(num * 1000 - 10);
        } catch (InterruptedException ie) {
          throw new RuntimeException(ie);
        }
        System.out.println("tick: " + System.currentTimeMillis());
      }
    },

    i * period, delay, TimeUnit.MILLISECONDS
  );
}

Thread.sleep(Integer.MAX_VALUE);
should produce 20 tasks which in total would tick once a second. But nope. You would get only 4 tasks, as corePoolSize does not expand if pool is unable to handle all scheduled tasks. The actual output would be something like:
tick: 1235810468265
tick: 1235810469237
tick: 1235810470278
tick: 1235810471280
tick: 1235810488274
tick: 1235810489236
tick: 1235810490277
tick: 1235810491299
The only hint for this is left in the javadocs for the ScheduledThreadPoolExecutor:
While this class inherits from ThreadPoolExecutor, a few of the inherited tuning methods are not useful for it. In particular, because it acts as a fixed-sized pool using corePoolSize threads and an unbounded queue, adjustments to maximumPoolSize have no useful effect.