javasqlmultithreadingparallel-processingexecutor

java Executor not executing all tasks if task count is not known in compile time


I have a very simple java code snippet:

  ExecutorService executor = null;          
      try {
          executor = Executors.newFixedThreadPool(4);             
          for (int i = 0; i < 10; i++) {                
              executor.submit( () -> processRule(rule_queue.poll()));           
            }
       }   

And here is the thing: if I replace the 10 (which is in my case the count of objects in the rule_queue queue with rule_queue.size() then not all tasks will be executed.

It is a very strange behaviour, for 1-2 fixedThreadPool threads it will work, but for 3 and above fixed threads will usually be only 5-7 tasks executed.

The problem is the count of objects in the queue comes from the database so I can't hardcode it into the for loop.

The method processRule do some database inserts/selects so I also don't want to open too many threads/connections, 4-5 SQL Selects simultaneously would be sufficient.

Thanks in adavance for any help how to run all tasks and how to run 4 in parallel and put all the others (could be up to 300) to the executors queue.

Edit: sorry forgot to write that after this code two additional lines are executor.shutdown() and waiting for finish.


Solution

  • I assume you replaced

    for (int i = 0; i < 10; i++) {                
        executor.submit( () -> processRule(rule_queue.poll()));           
    }
    

    with

    for (int i = 0; i < rule_queue.size(); i++) {
    //                  ^^^^^^^^^^^^^^^^^
        executor.submit( () -> processRule(rule_queue.poll()));           
    }
    

    The problem is that rule_queue.size() is being re-evaluated at each iteration. Consider the case where the initial queue size is 2.

    Iteration    i   rule_queue.size()   result
    ---------    -   -----------------   ------
        1        0           2           submit
        2        1           1           exit loop
    

    So only half of your rules will be submitted. What you want instead is:

    while(rule_queue.size() > 0) {
        executor.submit( () -> processRule(rule_queue.poll()));           
    }
    

    You would have immediately seen this if you had stepped through the code in your IDE debugger.