6

In my application I have 4 distinct processes, which run permanently with some small pauses.

The current version of code executes each process in a separate old-school thread:

Thread nlpAnalyzer = new Thread(() -> {

    // infine lop for auto restore in case of crash
    //noinspection InfiniteLoopStatement
    while (true) {
        try {
            // this method should run permanently, pauses implemented internally
            NLPAnalyzer.analyzeNLP(dbCollection);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

nlpAnalyzer.setName("im_nlpAnalyzer");
nlpAnalyzer.start();

Now I would like to refactor this code with use of ExecutorService. In order to do that I can use at least two approaches:

  • newFixedThreadPool(numOfProc);
  • numOfProc * newSingleThreadExecutor().

My questions:

  1. Is there any reason why I should prefer one option over another?

  2. What is more accepted to generate a thread pool with X threads or generate X newSingleThreadExecutors?

  3. Pro et contra of each of the approach?

Mike
  • 14,010
  • 29
  • 101
  • 161
  • Option 1 is more common and has least overhead. – Spotted Apr 04 '16 at 09:04
  • On another note, You can re-write the code inside infinite loop as a `Runnable` that posts itself again on as executor service, when run. That way, multiple tasks can run even on a single thread. – S.D. Apr 04 '16 at 13:19

2 Answers2

4

Given each task is a infinite loop, what I would used is a

newCachedThreadPool();

This would create a thread for every task which needed it (and no more)

The benefit of using a single threaded pool each is you could shutdown the pool individually, or give each thread a name, but if you don't need this, it's just overhead.

Note: you can change the name of a thread with setName("My task") which might be useful for debugging/profiling purposes.

One of the tricks of using an ExecutorService is that it captures any uncaught exception/errors and places it in the Future object returned. Often this Future is discarded which means that if your task dies unexpectedly it might also do it silently.

I suggest you do a try/catch(Throwable) outside the loop and log it so you can see if the thread ever dies unexpectedly. e.g OutOfMemoryError

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • As far as I know, I can assign a separate thread name even into `newFixedThreadPool`, not only with `newSingleThreadExecutor`. Is there any performance difference between define 1 `newFixedThreadPool` for X threads or X `newSingleThreadExecutor`s? – Mike Apr 04 '16 at 12:42
  • 1
    @MikeB. You can assign a separate thread name, but not one based on the purpose of the task which might be more useful. I would do whatever you feel is clearer, no matter which solution you chose, a `Thread` still does the work. – Peter Lawrey Apr 04 '16 at 14:41
1

I don't see any benefit for below option except shutting down individual executor.

numOfProc * newSingleThreadExecutor()

But you have more options. I prefer one of below three options from Executors.

newFixedThreadPool
newCachedThreadPool
newWorkStealingPool

Refer to below SE questions for relevant queries :

Java's Fork/Join vs ExecutorService - when to use which?

How to properly use Java Executor?

Difference between Executors.newFixedThreadPool(1) and Executors.newSingleThreadExecutor()

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211