javaexecutorservice

Main thread waiting for executor service


Is there a way to print "noise3" before all the "Aroma" are printed? The rest of the main method always waits for the executorservice shutdown, but I want them to run simultaneously

import java.util.concurrent.*;

public class Class2 {
    public static void main(String[] args) {
        Runnable task = ()->{
            for(int i=0;i<5;++i){
                try { Thread.sleep(1_000); } catch (Exception e) { e.printStackTrace(); } 
                System.out.println("Aroma");
            }
        };

        try(var service = Executors.newFixedThreadPool(5)){
            for(int i=0;i<5;++i){
                service.submit(task);
                try { Thread.sleep(2_000); } catch (Exception e) { e.printStackTrace(); }
                System.out.println("noise");
            }
            System.out.println("noise2");
        }

        System.out.println("noise3");
    }
}

Solution

  • No, "noise3" must wait, executes last

    You asked:

    print "noise3" before all the "Aroma" are printed

    Your code as currently written does exactly the opposite of what you want.

    ExecutorService#close

    The try-with-resources code ends with an implicit call to ExecutorService#close. That method blocks until all tasks assigned to the executor service resolve (or 24 hours elapse; see source code).

    So your System.out.println("noise3"); cannot run until the call to ExecutorService#close exits.

    try( ExecutorService executorService = Executors.… )
    {
        …
    }
    // Flow-of-control blocks here until `ExecutorService#close` exits when all tasks resolve or 24-hours elapse.
    System.out.println("noise3");
    

    If you want "noise3" first, reverse the order of your code.

    System.out.println("noise3");  // To execute first, place this code first. 
    try( ExecutorService executorService = Executors.… )
    {
        …
    }
    
    // Flow-of-control blocks here until `ExecutorService#close` exits when all tasks resolve or 24-hours elapse.
    

    Tip: Always include that // Flow-of-control blocks here until ExecutorService#close exits when all tasks resolve or 24-hours elapse. comment in your code. It is crucial that anyone reading this code understands this issue.

    Caveat: Be aware that output from System.out.println does not appear on the console in chronological order when called across threads. At least include, and study, a timestamp (Instant.now()) if you care about the sequence. Better yet, instead of System.out.println, use a proper logging tool, or collect messages in a thread-safe SequencedCollection.


    Tip: Use var only on simple, utterly obvious code. Threading and concurrency is not a place to be clever.

    Similarly, use precise descriptive naming such as executorService rather than service.

    I always write code with a thought to how it will read through blurry eyes during an 3 AM emergency debugging session.