4

I am using the Executor framework specifically Executors.newCachedThreadPool();
I have a list of Runnables e.g. 100.
The first 50, each create a value (stored in a list) to be used by the last 50.
I thought that if I pass the Runnables in the executor.execute() in the order they are in the list, they would be also executed in the same order.
But this is not happening.
The tasks seem to be executed in random order and they are interleaved, not executed in sequence.
Is this how it is suppose to work? Any way to work around this problem?

Thanks

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • 5
    Executors.execute() does not make any ordering guarantees. Workers will take from the queue in order, but may be context-switched at any time before completion. Thus if you have 50 threads the list can skip up to 50 tasks ahead. – OrangeDog Dec 17 '10 at 12:45
  • Order is only guaranteed if you have one thread. Otherwise the next free thread will start the next available task. – Peter Lawrey Dec 17 '10 at 13:19

3 Answers3

10

You need to submit the jobs in two batches, or otherwise create an explicit "happens-before" relationship. Suggest building two batches of jobs and using invokeAll(batch1); invokeAll(batch2); The invokeAll() method will execute all of the tasks and block until they complete. You may need to wrap your Runnables as Callables, which you can do with Executors.callable(Runnable r). (@Cameron Skinner beat me to getting some code example, see that answer for more...)

The whole point of executors is to abstract away the specifics of execution, so ordering is not guaranteed unless explicitly stated. If you want strictly sequential execution, do it in the thread you're running in (simplest), do it in a single-threaded executor, ala Executors.newSingleThreadExecutor(), or explicitly synchronize the tasks. If you want to do the latter, you could use a barrier or latch and have the dependent tasks block on the barrier/latch. You could also have the first block of tasks implement Callable, return Future, and have the dependent tasks call myFuture.get() which would cause them to block until the results are returned.

If you say more about your specific application, we might be able to help more specifically.

andersoj
  • 22,406
  • 7
  • 62
  • 73
  • Thanks for the detailed info!!!Could you elaborate more on the usage of barrier please?I am not sure I got that part – Cratylus Dec 17 '10 at 12:50
  • 1
    @user384706: Well, a barrier is probably overkill for this task, but conceptually if you have batches of tasks that represent a unit of work that need to complete together before another batch can start up again, you can use a http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CyclicBarrier.html to effect this. It's heavyweight in your case -- more commonly used when you have lots of iterations, and you only have batch1 -> batch2 – andersoj Dec 17 '10 at 12:58
7

That is the correct behaviour. You have no guarantees about which order the Runnables are executed.

Executors run in parallel, whereas it seems that you want the tasks run in serial. You can either submit the first 50 jobs, wait for them to finish, then submit the second 50 jobs, or (if the order of execution is important) just run them all in a single thread.

For example,

for (Future<Whatever> f: service.invokeAll(first50tasks)) {
    addResultToList(f.get());
}
Future<Whatever> output = service.invokeAll(second50tasks);
Cameron Skinner
  • 51,692
  • 2
  • 65
  • 86
  • What is the difference of doing `invokeAll(tasks)` than submiting each callable in turn? Is it more optimized to do `invokeAll`? – Cratylus Dec 17 '10 at 17:05
  • 2
    `invokeAll` returns only when all the tasks are complete so you don't need to write code for waiting. – Cameron Skinner Dec 17 '10 at 17:13
2

Perhaps you could execute the first 50, shutdown and awaitTermination, and only then execute the other 50? See this answer for some sample code.

Community
  • 1
  • 1
Fabian Steeg
  • 44,988
  • 7
  • 85
  • 112
  • I am not sure how to use awaitTermination;. Javadoc says: Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens firstI do not want to shutdown the executor and not sure if I want to timeout – Cratylus Dec 17 '10 at 12:46
  • There's no reason to throw away a perfectly good executor just to ensure the jobs are complete... `invokeAll()` does this, or you can collect up `Future`s and wait for them to complete. – andersoj Dec 17 '10 at 12:49
  • @user384706: A code sample on how to use `awaitTermination` is linked from my answer. However, andersoj's answer sounds like the right thing to do. – Fabian Steeg Dec 17 '10 at 15:08