Выберите между ExecutorService submit и ExecutorService
Как выбрать ExecutorService submit или execute, если возвращаемое значение не касается меня?
Если я тестирую оба, я не видел различий между ними, кроме возвращаемого значения.
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
Ответы
Ответ 1
Существует разница в отношении обработки исключений/ошибок.
Задача, поставленная в очередь с execute()
, которая генерирует некоторый Throwable
, приведет к вызову UncaughtExceptionHandler
для Thread
, запускающего задачу. По умолчанию UncaughtExceptionHandler
, который обычно печатает трассировку стека Throwable
на System.err
, будет вызываться, если пользовательский обработчик не установлен.
С другой стороны, a Throwable
, сгенерированный задачей, поставленной в очередь с submit()
, привяжет Throwable
к Future
, который был получен из вызова submit()
. Вызов get()
на то, что Future
будет генерировать ExecutionException
с исходным Throwable
в качестве причины (доступный путем вызова getCause()
на ExecutionException
).
Ответ 2
выполнить: использовать его для запуска и перезапуска вызовов
отправить. Используйте его для проверки результата вызова метода и принятия соответствующих действий в Future
, возвращенных вызовом
От javadocs
submit(Callable<T> task)
Отправляет задачу возврата значения для выполнения и возвращает будущее представляя ожидающие результаты задачи.
Future<?> submit(Runnable task)
Отправляет Runnable задачу для выполнения и возвращает будущее, представляющее, что Задача.
void execute(Runnable command)
Выполняет заданную команду в будущем. Команда может выполняться в новом потоке, в объединенном потоке или в вызывающем потоке, по усмотрению реализации Executor.
При использовании 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()?
- Вставьте код своей задачи (либо Runnable, либо Callable) с помощью try {} catch {} block code
- Реализация
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
Ответ 3
Если вы не заботитесь о возвращаемом типе, используйте execute. это то же самое, что и submit, только без возврата Будущего.
Ответ 4
Взято из Джавадока:
Метод submit
расширяет базовый метод {@link Executor # execute
} путем создания и возвращая {@link Future}, которое может быть использовано для отмены выполнения и/или ожидания завершение.
Лично я предпочитаю использовать execute, потому что он чувствует себя более декларативным, хотя это действительно вопрос личных предпочтений.
Чтобы предоставить дополнительную информацию: в случае реализации ExecutorService
реализация ядра, возвращаемая вызовом Executors.newSingleThreadedExecutor()
, является ThreadPoolExecutor
.
Вызов submit
предоставляется родительским AbstractExecutorService
, и все вызовы выполняются внутренне. выполнение переопределяется/предоставляется непосредственно ThreadPoolExecutor
.
Ответ 5
Из Javadoc:
Команда может выполняться в новом потоке, в объединенном потоке или в вызывающем потоке, по усмотрению реализации Executor.
Таким образом, в зависимости от реализации Executor
вы можете обнаружить, что отправляющий поток блокируется во время выполнения задачи.
Ответ 6
Полный ответ - это композиция из двух ответов, которые были опубликованы здесь (плюс бит "лишний" ):
- Отправляя задачу (против ее выполнения), вы возвращаете будущее, которое может быть использовано для получения результата или отмены действия. У вас нет такого контроля, когда вы
execute
(потому что его идентификатор возвращаемого типа void
)
-
execute
ожидает Runnable
, а submit
может принимать как Runnable
, так и Callable
в качестве аргумента (для получения дополнительной информации о различии между ними см. ниже).
-
execute
сразу же удаляет любые неконтролируемые исключения (он не может выставить проверенные исключения!!!), а submit
связывает любое исключение с будущим, которое возвращается в результате, и только когда вы вызываете future.get()
будет выбрано исключение (завернутое). Throwable, который вы получите, является экземпляром ExecutionException
, и если вы вызовете этот объект getCause()
, он вернет оригинал Throwable.
Еще несколько (связанных) точек:
- Даже если задача, для которой требуется
submit
, не требует возврата
в результате вы можете использовать Callable<Void>
(вместо использования Runnable
).
- Отмена заданий может быть выполнена с помощью механизма interrupt. Здесь пример о том, как реализовать политику отмены
Подводя итог, лучше использовать submit
с Callable
(vs. execute
с Runnable
). И я приведу цитату из "Java concurrency на практике". Брайан Гетц:
6.3.2 Задачи, выполняемые с учетом результатов: Callable and Future
Структура Executor использует Runnable в качестве основного представления задачи. Runnable - довольно ограничение абстракции; run не может вернуть значение или бросить флажок исключений, хотя он может иметь побочные эффекты, такие как запись в журнал файл или размещение результата в общей структуре данных. Многие задачи эффективно отложенные вычисления - выполнение запроса к базе данных, выборка ресурс по сети или вычисление сложной функции. Для эти типы задач, Callable - лучшая абстракция: он ожидает что основная точка входа, вызов, вернет значение и предвидит что это может вызвать исключение .7 Исполнители включают в себя несколько полезных методы для переноса других типов задач, включая Runnable и java.security.PrivilegedAction, с Callable.