example ejemplo java multithreading threadpool executorservice

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()

  1. Envuelva su Callable or Runnable code in try{} catch{} block

    O

  2. Mantenga la future.get() call in try{} catch{} block

    O

  3. implemente su propio ThreadPoolExecutor y anule el método afterExecute

En cuanto a la gira otras consultas en

invokeAll :

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.

invokeAny :

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