3

I have some code that makes heavy use of a thread pool, which I use by creating Collection<Callable<T>> tasks, and calling ExecutorService.invokeAll(tasks).

for (Future<Object> future : threadPool.invokeAll(tasks)) {
  Object object = future.get();
  // Calling thread effectively blocks on invokeAll().
}

In my app, the size of tasks varies a lot. In fact, most of the time the ExecutorService.invokeAll() is called with a single task. The implementation of invokeAll() that I'm using calls ThreadPoolExecutor.execute(), whose implementation appears to always run the task in the thread pool (never in the calling thread).

In the case of a single task, would it be more efficient to call the task in the current thread rather than send it off to another thread?

Jacob Marble
  • 28,555
  • 22
  • 67
  • 78

2 Answers2

3

In the case of a single task, would it be more efficient to call the task in the current thread rather than send it off to another thread?

Yes, it would be more efficient. That's not an interesting question though. The interesting questions are how inefficient it is - which will depend on what your task is doing - and whether you're doing this enough in your application for it to be significant overall.

We don't have enough information to evaluate that for you. If you're executing a single trivial task ("fetch a value from a map") millions of times per second, then all the indirection via the thread pool could make a real difference. If your tasks actually do a significant amount of work, then it's almost certainly not worth the extra code of special-casing the case where you've only got a single task.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Right, threads are relatively lightweight, especially when they are already created, just waiting in a pool. In the case of my app, I'm leaning toward "more efficient" because even if the task is IO-bound (not consuming a lot of CPU time), I'm blocking two threads for one task: the calling thread and the pool thread. If the calling thread executes the task then the pool thread can be used for other tasks. – Jacob Marble Jun 27 '12 at 06:07
  • @JacobMarble: Sure, but how much of a problem do you think that is? How often does your thread pool actually fill up, forcing other tasks to wait? I suspect that in the vast majority of cases you'd be swapping a blocking calling thread for an idle thread pool thread, which wouldn't make any performance difference. – Jon Skeet Jun 27 '12 at 06:09
  • The thread pool occasionally experiences contention, which makes real customers grouchy. Does the code snippet added to the question help? There's nothing else going on in the calling thread. – Jacob Marble Jun 27 '12 at 06:14
  • @JacobMarble: The thread pool will still probably experience contention - just very slightly more rarely. (Unless you've got a *lot* of threads doing this very often.) Increasing the size of the thread pool could help counter that. Ultimately though, there are far too many variables here for us to accurately predict the effect. Only you can test it, which is what you should do if you have evidence to suggest you've got a real problem. – Jon Skeet Jun 27 '12 at 06:18
2

Of course there is going to be some reduction in the total cost of executing some code if you just run it right in place. You're not constructing the collection, queueing and de-queueing, waking up a worker thread, adding another thread to the running total the CPU has to timeshare, moving data from one stack to heap to another stack, etc.

More efficient does not make it more 'correct' though. The current thread is usually doing something that is rather time sensitive, and hands off work to the pool so that it can get back to whatever task is its primary concern, without waiting for the work to be done.

If "currentThread" is the main GUI thread, and you're passing off say, a print spool job that takes 30 seconds, an implementation of ExecutorService that says "Oh, well, there's only one job here, I'll just run it in the current thread" would be very wrong in deed, and your user will let you know how wrong it is with their 30 second hang ups!

Affe
  • 47,174
  • 11
  • 83
  • 83