Choose between ExecutorService's submit and ExecutorService's execute
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
).
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 ExecuteSubmitDemocreating servicea and b=4:0
Same code throws by replacing submit()
with execute
() :
Replace
service.submit(new Runnable(){
with
service.execute(new Runnable(){
output:
java ExecuteSubmitDemocreating servicea and b=4:0Exception 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()?
- Embed your Task code ( Either Runnable or Callable implementation) with try{} catch{} block code
- 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 ExecuteSubmitDemocreating servicea and b=4:0java.lang.ArithmeticException: / by zero
if you dont care about the return type, use execute. it's the same as submit, just without the return of Future.