Difference between ExecutorService submit and execute method

Upasana | June 23, 2022 | 2 min read | 17 views


A common multi-threading question that’s generally asked in investment banking interviews (Barclays, Citibank, Morgan Stanley).

Lets first see the relation between ExecutorService and Executor interface.

execute submit
ExecutorService extends Executor
Main differences between the two methods:
  1. The execute() method is declared in Executor interface while submit() method is declared in ExecutorService interface.

  2. The submit() method can accept both Runnable as well as Callable tasks, but execute() method can only accept a Runnable Task.

  3. execute() method returns void while submit() method returns Future object. Using future you can cancel the execution or retrieve the results of computation done by runnable/callable task.

  4. There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted with execute this exception will go to the uncaught exception handler (when you don’t have provided one explicitly, the default one will just print the stack trace to System.err). If you submitted the task with submit any thrown exception, checked exception or not, is then part of the task’s return status. For a task that was submitted with submit and that terminates with an exception, the Future.get will re-throw this exception, wrapped in an ExecutionException.

Final advise

You should prefer to use submit() method because it gives more flexibility to the programmer in terms of execution control i.e. you can check status of task, cancel a task or get the results of task. Additionally a better exception handling is possible using submit().

Finally, a working example of ExecutorService.

ExecutorService Example
import java.util.concurrent.*;

public class ExecutorExample {

    public void example() {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Callable<String> futureTask =
                new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        return searcher.search(target);
                    }
                };
        final Future<String> future = executor.submit(futureTask);
        try {
            String result = future.get();
            System.out.println("result = " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        executor.shutdownNow();
    }

    public static void main(String[] args) {
        ExecutorExample test = new ExecutorExample();
        test.example();
    }
}

Shortened version of the above program using lambda expressions:

import java.util.concurrent.*;

public class ExecutorExample {

    public void testSubmit() {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Callable<String> futureTask = () -> {
            //TODO: Implement actual method
            return "Foo";
        };
        try {
            final Future<String> future = executor.submit(futureTask);
            String result = future.get();
            System.out.println("result = " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        executor.shutdownNow();
    }

    public static void main(String[] args) {
        ExecutorExample example = new ExecutorExample();
        example.testSubmit();
    }
}

Top articles in this category:
  1. Difference between Callable and Runnable Interface
  2. What is difference between sleep() and wait() method in Java?
  3. What is difference between Vector and ArrayList, which one shall be preferred
  4. What is difference between HashMap and HashSet
  5. Difference between HashMap, LinkedHashMap and TreeMap
  6. Submit Form with Java 11 HttpClient - Kotlin
  7. Difference between Implementing Runnable and Extending Thread

Recommended books for interview preparation:

Find more on this topic: