1

I am using JDK/Java 19 in Windows 11 x64, IntelliJ IDEA 2022 Ultimate.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ZooInfo {

    public static void main(String[] args) {
        ExecutorService executorService = null;
        Runnable runnable1 = () -> System.out.println("Printing zoo inventory");
        Runnable runnable2 = () -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("Printing record " + i);
            }
        };
        try {
            executorService = Executors.newSingleThreadExecutor();
            System.out.println("Begin");
            executorService.execute(runnable1);
            executorService.execute(runnable2);
            executorService.execute(runnable1);
            System.out.println("End.");
        } finally {
            if (executorService != null) {
                executorService.shutdown();
            }
        }
    }

}

// Result:

// Begin
// End.
// Printing zoo inventory
// Printing record 0
// Printing record 1
// Printing record 2
// Printing zoo inventory

I read page 850, book OCP Oracle Certified Professional Java SE 11 Developer - Complete Study Guide), they said

With a single-thread executor, results are guaranteed to be executed sequentially.

Why the order was not guaranteed by Executors.newSingleThreadExecutor() ? ("end" not at the end of line in console's result.)

Vy Do
  • 46,709
  • 59
  • 215
  • 313

3 Answers3

6

shutdownAndAwaitTermination boilerplate

You neglected to wait for the executor service to complete its work.

You ignored all the boilerplate code given to you in the shutdownAndAwaitTermination method shown in the Javadoc for ExecutorService.

Add a call to that boilerplate after you submit your Runnable objects. Now your main thread will wait for the executor’s thread(s) to finish their tasks.

executorService = Executors.newSingleThreadExecutor();
System.out.println("Begin");
executorService.execute(runnable1);
executorService.execute(runnable2);
executorService.execute(runnable1);
shutdownAndAwaitTermination( executorService ) ;  // Block here to wait for executor service to complete its assigned tasks. 
System.out.println("End.");

Your original thread happened to finish its work earlier than did the thread of the executor service. That is the nature of independent threads: various threads accomplish various amounts of work in various amounts of time.

Project Loom

Project Loom is an effort to bring new capabilities to the Java concurrency facilities.

The structured concurrency feature being incubated now in Java 19 might make it even easier to accomplish your goal of having several tasks performed as a group on background threads.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

Your program has two threads:

  1. The main one, from which you invoke executorService.execute and all the rest.
  2. The Executors.newSingleThreadExecutor()'s thread

The runnables you pass to the newSingleThreadExecutor will indeed be run sequentially on that thread, but it doesn't mean everything in your program runs sequentially relative to those runnables. Your main thread will keep going, unless you somehow wait on the main thread for the tasks to complete (for example, by invoking executorService.shutdown() and then awaitTermination(...) to wait for the existing jobs to finish). You could also use submit rather than execute for each runnable; that would give you back a Future, which you can then call get(...) on to wait for it to finish (you would have to do this for each runnable. executorService.invokeAll(...) makes this a bit easier.

yshavit
  • 42,327
  • 7
  • 87
  • 124
-1

Because main method is independent with executorService = Executors.newSingleThreadExecutor();

Vy Do
  • 46,709
  • 59
  • 215
  • 313