Search code examples
javamultithreadingconcurrencyexecutorservicejava.util.concurrent

ExecuterService stopped processing one thread out of two


  1. I have a list of 40000 records that needs to be processed in a for loop. Since I have a two processor system. I have created a fixedThreadPool like this:

    int threads = Runtime.getRuntime().availableProcessors(); ExecutorService service = Executors.newFixedThreadPool(threads);

  2. And divided my ArrayList into two sublists. For each of these sublists, I have created a Callable that performs the same function (involves iterating over the sublist and doing some processing) and returns me a Future object.

  3. I submitted both these Callable using executorServiceObject.submit(callable) and added the returned Future object into my list of Future objects

Here is my question:

I have written a System.Out.printLn("Processed Item" +item.id) // consider item as the name of reference variable for current iteration

Everything was fine for some time and i could see two threads working simutaneously. But after some time, one of the threads have stopped processing. Only one thread is running. (I know this because i can see on the console that the id's given to thread 2 are not being printed anymore).

Does anyone know how this happened? I mean why ExecutorService stopped running 2nd thread.

Thanks for your help in advance.

Adding sample code as I should have done before:

public List<Output> processInputs(List<Input> inputs)
        throws InterruptedException, ExecutionException {

    int threads = Runtime.getRuntime().availableProcessors();
    ExecutorService service = Executors.newFixedThreadPool(threads);

    List<Future<Output>> futures = new ArrayList<Future<Output>>();
    for (final Input input : inputs) {
        Callable<Output> callable = new Callable<Output>() {
            public Output call() throws Exception {
                Output output = new Output();
                // process your input here and compute the output
                return output;
            }
        };
        futures.add(service.submit(callable));
    }

    service.shutdown();

    List<Output> outputs = new ArrayList<Output>();
    for (Future<Output> future : futures) {
        outputs.add(future.get());
    }
    return outputs;

Solution

  • Everything was fine for some time and i could see two threads working simultaneously. But after some time, one of the threads have stopped processing. Only one thread is running. (I know this because i can see on the console that the id's given to thread 2 are not being printed anymore).

    I suspect that your processing thread has thrown an exception. The Future.get() method can throw ExecutionException "if the computation threw an exception".

    // the following might throw an exception if the background job threw
    outputs.add(future.get());
    

    If there was a NPE, an IOException, etc. thrown by your "process your input" code then that exception is thrown by the Callable and stored in the Future so it can be thrown by the get() method but wrapped in an ExecutionException. This is useful so the thread that is waiting can get and and handle (log, etc.) the exception thrown by the background thread.

    Instead of just having your processInputs(...) method throw the exception to the caller where it might be getting lost, I'd do something like the following in your while loop:

    try {
       outputs.add(future.get());
    } catch (InterruptedException ie) {
       // always a good pattern if the thread that is waiting was interrupted
       Thread.currentThread().interrupt();
       return;
    } catch (ExecutionException ee) {
       // somehow log the error
       logger.error("Computation failed to process", ee);
       // now continue and get the next future in the list
    }
    

    If you don't catch and properly handle that ExecutionException then the processing exception will also kill the thread that calls processInputs(...).