java - ejemplo - runnable executorservice example
diferencia entre executor.submit y executor.execute en este código en Java? (5)
Como puede ver desde la execute(Runnable)
no devuelve nada.
Sin embargo, submit(Callable<T>)
devuelve un objeto Future
que permite una forma de cancelar programáticamente el hilo en ejecución más adelante, así como obtener la T
que se devuelve cuando se completa el Callable
. Ver JavaDoc of Future para más detalles
Future<?> future = executor.submit(longRunningJob);
...
//long running job is taking too long
future.cancel(true);
Además, si future.get() == null
y no lanza ninguna excepción, Runnable se ejecutará con éxito
Estoy aprendiendo a usar exectorServices
para agrupar threads
y enviar tareas. Tengo un programa simple a continuación
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Processor implements Runnable {
private int id;
public Processor(int id) {
this.id = id;
}
public void run() {
System.out.println("Starting: " + id);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("sorry, being interupted, good bye!");
System.out.println("Interrupted "+Thread.currentThread().getName());
e.printStackTrace();
}
System.out.println("Completed: " + id);
}
}
public class ExecutorExample {
public static void main(String[] args) {
Boolean isCompleted=false;
ExecutorService executor = Executors.newFixedThreadPool(2);
for(int i=0; i<5; i++) {
executor.execute(new Processor(i));
}
//executor does not accept any more tasks but the submitted tasks continue
executor.shutdown();
System.out.println("All tasks submitted.");
try {
//wait for the exectutor to terminate normally, which will return true
//if timeout happens, returns false, but this does NOT interrupt the threads
isCompleted=executor.awaitTermination(100, TimeUnit.SECONDS);
//this will interrupt thread it manages. catch the interrupted exception in the threads
//If not, threads will run forever and executor will never be able to shutdown.
executor.shutdownNow();
} catch (InterruptedException e) {
}
if (isCompleted){
System.out.println("All tasks completed.");
}
else {
System.out.println("Timeout "+Thread.currentThread().getName());
}
}
}
No tiene nada de lujoso, pero crea dos threads
y envía 5 tareas en total. Después de que cada thread
completa su tarea, toma la siguiente, en el código anterior, uso executor.submit
. También cambié a executor.execute
. Pero no veo ninguna diferencia en la salida. ¿De qué manera son diferentes los métodos de submit and execute
? Esto lo dice la API
El método de envío extiende el método base Executor.execute (java.lang.Runnable) creando y devolviendo un futuro que se puede usar para cancelar la ejecución y / o esperar la finalización. Los métodos invokeAny e invokeAll realizan las formas más comunes de ejecución masiva, ejecutan una colección de tareas y luego esperan que se complete al menos una o todas. (Class ExecutorCompletionService se puede usar para escribir variantes personalizadas de estos métodos).
Pero no es claro para mí, ¿qué significa exactamente? Gracias
Enviar - Devuelve objeto futuro, que se puede usar para verificar el resultado de la tarea enviada. Se puede usar para cancelar o verificar IsDone, etc.
Ejecutar - no devuelve nada.
La diferencia es que execute
simplemente inicia la tarea sin más preámbulos, mientras que submit
devuelve un objeto Future
para administrar la tarea. Puede hacer lo siguiente con el objeto Future
:
- Cancele la tarea prematuramente, con el método
cancel
. - Espere a que la tarea termine de ejecutarse, con
get
.
La interfaz Future
es más útil si envía un Callable
al grupo. El valor de retorno del método de call
se devolverá cuando llame a Future.get
. Si no mantiene una referencia al Future
, no hay diferencia.
básicamente ambas llamadas se ejecutan, si quieres un objeto futuro deberás llamar al método submit () aquí desde el documento
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
como puede ver, java realmente no tiene forma de iniciar un hilo que no sea llamar al método run (), IMO. ya que también encontré que el método Callable.call()
se llama dentro del método run()
. por lo tanto, si el objeto es invocable, aún llamaría al método run()
, que a su vez llamaría al método call()
desde doc.
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
execute:
usarlo para disparar y olvidar llamadas
submit:
Úselo para inspeccionar el resultado de la llamada al método y tomar las medidas adecuadas sobre el Future
objetado devuelto por la llamada
Diferencia principal: manejo de Exception
submit()
oculta la Exception
manejada en el marco mismo.
execute()
arroja una Exception
controlada.
Solución para manejar Excepciones con submit()
Envuelva su
Callable or Runnable code in try{} catch{} block
O
Mantenga la
future.get() call in try{} catch{} block
O
implemente su propio
ThreadPoolExecutor
y anule el métodoafterExecute
En cuanto a la gira otras consultas en
Ejecuta las tareas dadas, devolviendo una lista de futuros que mantienen su estado y resultados cuando todo se completa o expira el tiempo de espera, lo que ocurra primero.
Ejecuta las tareas dadas, devolviendo el resultado de uno que se ha completado con éxito (es decir, sin lanzar una excepción), si lo hace antes de que transcurra el tiempo de espera dado.
Use invokeAll
si desea esperar a que se completen todas las tareas enviadas.
Use invokeAny
si está buscando completar con éxito una tarea de N tareas enviadas. En este caso, las tareas en curso se cancelarán si una de las tareas finaliza correctamente.
Publicación relacionada con el ejemplo del código:
Elija entre la presentación de ExecutorService y la ejecución de ExecutorService