Choose between ExecutorService's submit and ExecutorService's execute

JavaMultithreadingExecutorservice

Java Problem Overview


How should I choose between ExecutorService's submit or execute, if the returned value is not my concern?

If I test both, I didn't see any differences among the two except the returned value.

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());

Java Solutions


Solution 1 - Java

There is a difference concerning exception/error handling.

A task queued with execute() that generates some Throwable will cause the UncaughtExceptionHandler for the Thread running the task to be invoked. The default UncaughtExceptionHandler, which typically prints the Throwable stack trace to System.err, will be invoked if no custom handler has been installed.

On the other hand, a Throwable generated by a task queued with submit() will bind the Throwable to the Future that was produced from the call to submit(). Calling get() on that Future will throw an ExecutionException with the original Throwable as its cause (accessible by calling getCause() on the ExecutionException).

Solution 2 - Java

execute: Use it for fire and forget calls

submit: Use it to inspect the result of method call and take appropriate action on Future objected returned by the call

From javadocs

submit(Callable<T> task)

> Submits a value-returning task for execution and returns a Future representing the pending results of the task.

Future<?> submit(Runnable task)

> Submits a Runnable task for execution and returns a Future representing that task.

void execute(Runnable command)

> Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

You have to take precaution while using submit(). It hides exception in the framework itself unless you embed your task code in try{} catch{} block.

Example code: This code swallows Arithmetic exception : / by zero.

import java.util.concurrent.*;
import java.util.*;

public class ExecuteSubmitDemo{
	public ExecuteSubmitDemo()
	{
		System.out.println("creating service");
		ExecutorService service = Executors.newFixedThreadPool(10);
		//ExtendedExecutor service = new ExtendedExecutor();
		service.submit(new Runnable(){
				 public void run(){
					int a=4, b = 0;
					System.out.println("a and b="+a+":"+b);
					System.out.println("a/b:"+(a/b));
					System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
				 }
			});
		service.shutdown();
	}
	public static void main(String args[]){
		ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
	}
}

output:

java ExecuteSubmitDemo
creating service
a and b=4:0

Same code throws by replacing submit() with execute() :

Replace

service.submit(new Runnable(){

with

service.execute(new Runnable(){

output:

java ExecuteSubmitDemo
creating service
a and b=4:0
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:14)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

How to handle the these type of scenarios while using submit()?

  1. Embed your Task code ( Either Runnable or Callable implementation) with try{} catch{} block code
  2. Implement CustomThreadPoolExecutor

New solution:

import java.util.concurrent.*;
import java.util.*;

public class ExecuteSubmitDemo{
	public ExecuteSubmitDemo()
	{
		System.out.println("creating service");
		//ExecutorService service = Executors.newFixedThreadPool(10);
		ExtendedExecutor service = new ExtendedExecutor();
		service.submit(new Runnable(){
				 public void run(){
					int a=4, b = 0;
					System.out.println("a and b="+a+":"+b);
					System.out.println("a/b:"+(a/b));
					System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
				 }
			});
		service.shutdown();
	}
	public static void main(String args[]){
		ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
	}
}

class ExtendedExecutor extends ThreadPoolExecutor {

   public ExtendedExecutor() { 
	   super(1,1,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
   }
   // ...
   protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future<?>) {
       try {
         Object result = ((Future<?>) r).get();
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       System.out.println(t);
   }
 }

output:

java ExecuteSubmitDemo
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero

Solution 3 - Java

if you dont care about the return type, use execute. it's the same as submit, just without the return of Future.

Solution 4 - Java

Taken from the Javadoc:

> Method submit extends base method {@link Executor#execute} by creating and > returning a {@link Future} that can be used to cancel execution and/or wait for > completion.

Personally I prefer the use of execute because it feels more declarative, although this really is a matter of personal preference.

To give more information: in the case of the ExecutorService implementation, the core implementation being returned by the call to Executors.newSingleThreadedExecutor() is a ThreadPoolExecutor.

The submit calls are provided by its parent AbstractExecutorService and all call execute internally. execute is overridden/provided by the ThreadPoolExecutor directly.

Solution 5 - Java

From the Javadoc:

> The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

So depending on the implementation of Executor you may find that the submitting thread blocks while the task is executing.

Solution 6 - Java

The full answer is a composition of two answers that were published here (plus a bit "extra"):

  • By submitting a task (vs. executing it) you get back a future which can be used to get the result or cancel the action. You don't have this kind of control when you execute (because its return type id void)
  • execute expects a Runnable while submit can take either a Runnable or a Callable as an argument (for more info about the difference between the two - see below).
  • execute bubbles up any unchecked-exceptions right away (it cannot throw checked exceptions!!!), while submit binds any kind of exception to the future that returns as a result, and only when you call future.get() a the (wrapped) exception will be thrown . The Throwable that you'll get is an instance of ExecutionException and if you'll call this object's getCause() it will return the original Throwable.

A few more (related) points:

  • Even if the task that you want to submit does not require returning a result, you can still use Callable<Void> (instead of using a Runnable).
  • Cancellation of tasks can be done using the interrupt mechanism. Here's an example of how to implement a cancellation policy

To sum up, it's a better practice to use submit with a Callable (vs. execute with a Runnable). And I'll quote from "Java concurrency in practice" By Brian Goetz:

> 6.3.2 Result-bearing tasks: Callable and Future > > The Executor framework uses Runnable as its basic task representation. Runnable is a fairly > limiting abstraction; run cannot return a value or throw checked > exceptions, although it can have side effects such as writing to a log > file or placing a result in a shared data structure. Many tasks are > effectively deferred computations—executing a database query, fetching > a resource over the network, or computing a complicated function. For > these types of tasks, Callable is a better abstraction: it expects > that the main entry point, call, will return a value and anticipates > that it might throw an exception.7 Executors includes several utility > methods for wrapping other types of tasks, including Runnable and > java.security.PrivilegedAction, with a Callable.

Solution 7 - Java

Just adding to the accepted answer-

> However, exceptions thrown from tasks make it to the uncaught > exception handler only for tasks submitted with execute(); for tasks > submitted with submit() to the executor service, any thrown exception > is considered to be part of the task’s return status.

Source

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCheok Yan ChengView Question on Stackoverflow
Solution 1 - JavahochraldoView Answer on Stackoverflow
Solution 2 - JavaRavindra babuView Answer on Stackoverflow
Solution 3 - JavaStevenView Answer on Stackoverflow
Solution 4 - JavaSyntaxView Answer on Stackoverflow
Solution 5 - JavarxgView Answer on Stackoverflow
Solution 6 - JavaNir AlfasiView Answer on Stackoverflow
Solution 7 - Javaabhihello123View Answer on Stackoverflow