Как я должен выбрать между ExecutorService - х представить или выполнить , если возвращаемое значение не моя забота?
Если я тестирую оба, я не вижу никаких различий между ними, кроме возвращаемого значения.
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
источник
Runnable
завернуты вы в aTask
или нет, что вы не можете контролировать. Например, если выExecutor
на самом деле aScheduledExecutorService
, ваша задача будет внутренне обернута в a,Future
а неперехваченныеThrowable
s будут привязаны к этому объекту.Future
, конечно, имею в виду «завернутый или нет». См., Например, Javadoc для ScheduledThreadPoolExecutor # execute .выполнять : использовать его для огня и забыть о звонках
submit : используйте его, чтобы проверить результат вызова метода и предпринять соответствующие действия
Future
возражения, возвращенного вызовомИз javadocs
submit(Callable<T> task)
Future<?> submit(Runnable task)
void execute(Runnable command)
При использовании необходимо соблюдать меры предосторожности
submit()
. Он скрывает исключение в самой структуре, если вы не встраиваете код задачи вtry{} catch{}
блок.Пример кода: этот код проглатывает
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(); } }
выход:
java ExecuteSubmitDemo creating service a and b=4:0
Тот же код вызывает замену
submit()
наexecute
():Заменить
service.submit(new Runnable(){
с участием
service.execute(new Runnable(){
выход:
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)
Как справиться с подобными сценариями при использовании submit ()?
CustomThreadPoolExecutor
Новое решение:
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); } }
выход:
java ExecuteSubmitDemo creating service a and b=4:0 java.lang.ArithmeticException: / by zero
источник
если вам не важен возвращаемый тип, используйте execute. это то же самое, что и submit, только без возврата Future.
источник
Взято из Javadoc:
Лично я предпочитаю использовать execute, потому что он кажется более декларативным, хотя на самом деле это вопрос личных предпочтений.
Для получения дополнительной информации: в случае
ExecutorService
реализации основная реализация, возвращаемая вызовомExecutors.newSingleThreadedExecutor()
- этоThreadPoolExecutor
.Эти
submit
вызовы предоставляются своим родителемAbstractExecutorService
и все это требует выполнения внутренне. execute переопределяется / предоставляетсяThreadPoolExecutor
напрямую.источник
Из Javadoc :
Таким образом, в зависимости от реализации
Executor
вы можете обнаружить, что отправляющий поток блокируется во время выполнения задачи.источник
Полный ответ представляет собой композицию из двух ответов, которые были опубликованы здесь (плюс немного «лишнего»):
execute
(потому что его идентификатор типа возвратаvoid
)execute
Ожидает, что некотороеRunnable
времяsubmit
может принимать в качестве аргумента либо a,Runnable
либо aCallable
(дополнительную информацию о различиях между ними см. ниже).execute
мгновенно всплывает любые непроверенные исключения (он не может генерировать проверенные исключения !!!), в то время какsubmit
привязывает любое исключение к будущему, которое возвращается в результате, и только когда вы вызываетеfuture.get()
(обернутое) исключение, будет сгенерировано. Throwable, который вы получите, является экземпляром,ExecutionException
и если выgetCause()
вызовете этот объект, он вернет исходный Throwable.Еще несколько (связанных) моментов:
submit
, не требует возврата результата, вы все равно можете использоватьCallable<Void>
(вместо использованияRunnable
).Подводя итог, лучше использовать
submit
сCallable
(а неexecute
сRunnable
). Я процитирую книгу Брайана Гетца «Параллелизм в Java на практике»:источник
Просто добавив к принятому ответу -
Источник
источник