7

i currently have a list of classes every class starts a scheduler like this:

private ScheduledFuture<?> myTask;
private ScheduledExecutorService scheduler;

public startScheduler() {
scheduler = Executors.newScheduledThreadPool( 1 );
    myTask = scheduler.scheduleAtFixedRate(new Runnable() {
          // doing work here
     },
          delay,
          interval,
          TimeUnit.MILLISECONDS );
}

So every class basically starts it's own scheduler and only has one task. But as i understand now a scheduler can take and run more tasks in parallel. The tasks (or in my current program the schedulers) have different delay and interval values and the number of schedulers started is unknown to me (cause the user can start new ones and stop running ones). All schedulers run in parallel. So should i change my code in order to use only one scheduler? Should I prefer the "CachedThreadPool"?

Nick Robertson
  • 1,047
  • 4
  • 18
  • 41
Biene Maja
  • 313
  • 1
  • 3
  • 9

3 Answers3

4

Yes, you can use just one pool to schedule all your tasks. Also, if you need the ability to schedule tasks at time intervals as you are currently doing, you should stick with newScheduledThreadPool because newCachedThreadPool returns only an ExecutorService interface and not ScheduledExecutorService.

casablanca
  • 69,683
  • 7
  • 133
  • 150
  • Oh missed that. But how do i increase the ThreadPool then, cause as i said, the user can add and end tasks thus requiring more or less threads. – Biene Maja Feb 07 '12 at 04:26
  • @Biene Maja: The pool grows automatically as required. The parameter `1` that you pass is only the starting pool size. – casablanca Feb 07 '12 at 04:27
  • 2
    That doesn't seem to be true. – Biene Maja Feb 07 '12 at 04:50
  • 4
    I tried to test it here: http://pastebin.com/p6E1bt1N With 1 he seems to use only 1 Thread thus executing the first one and then after finishing exectuing the 2nd 5 times cause of the interval. With 2 he is running them concurrently. Thus running the 2nd every second. – Biene Maja Feb 07 '12 at 05:46
  • Hmm, you're right. The interface for `ScheduledExecutorService` doesn't seem to specify this behaviour explicitly and looking at the implementation of `ScheduledThreadPoolExecutor`, it seems that it only uses the core pool. I guess you'll have to then specify the maximum core pool size you need. – casablanca Feb 07 '12 at 05:54
1

I see it is surprise not only for me: ScheduledThreadPoolExecutor has a fixed threadpool size:

No. From http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html:

.... it acts as a fixed-sized pool using corePoolSize threads ...

Some other related links:

Why is there no scheduled cached thread pool provided by the Java Executors class?

http://coding.tocea.com/java/dmi_futile_attempt_to_change_maxpool_size_of_scheduled_thread_pool_executor/

Why does ScheduledThreadPoolExecutor only accept a fixed number of threads?

Have a look at test result:

public class AsyncExecutorTest {
   private static final ScheduledThreadPoolExecutor SCH_EXECUTOR = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
   private static final ExecutorService EXECUTOR = (ExecutorService) Executors.newCachedThreadPool();
   public static final int NUMBER = 10;

   @Test
   public void testSubmit() throws Exception {
      submit(EXECUTOR);
      submit(SCH_EXECUTOR);

      SCH_EXECUTOR.setMaximumPoolSize(100);
      submit(SCH_EXECUTOR);
      SCH_EXECUTOR.setCorePoolSize(100);
      submit(SCH_EXECUTOR);
   }

   private void submit(ExecutorService exe) throws InterruptedException {
      long start = System.currentTimeMillis();
      final CountDownLatch cdt = new CountDownLatch(NUMBER);
      for (int i = 0; i < NUMBER; i++) {
          exe.submit(new Runnable() {
          @Override
             public void run() {
                try {
                    Thread.sleep(1000);
                    cdt.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
          });
      }
      cdt.await();
      System.out.println(System.currentTimeMillis() - start);
   }
}

1002

5004

5001

1006

Suggested solution is:

 scheduledExecutor = new ScheduledThreadPoolExecutor(150); //max thread
 scheduledExecutor.setKeepAliveTime(10, TimeUnit.SECONDS);
 scheduledExecutor.allowCoreThreadTimeOut(true);  // allow terminate core idle threads

From example can be seen that max thread pool size could be changed not by setMaxPoolSize but by setCorePoolSize

Community
  • 1
  • 1
Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
0

Yes, I would suggest using a single scheduler.

Executors.newCachedThreadPool() returns an ExecutorService, not a ScheduledExecutorService, so I don't think that will work for you. I'd stick with newScheduledThreadPool()

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67