util thread newscheduledthreadpool isterminated invokeall example ejemplo concurrent java multithreading executorservice

newscheduledthreadpool - java executorservice thread pool



Elija entre la presentaciĆ³n de ExecutorService y la ejecuciĆ³n de ExecutorService (6)

Desde el execute :

El comando puede ejecutarse en un nuevo hilo, en un hilo agrupado o en el hilo de llamada, a discreción de la implementación del Ejecutor.

De modo que, dependiendo de la implementación de Executor , puede encontrar que el subproceso se bloquea cuando la tarea se está ejecutando.

¿Cómo debo elegir entre submit o execute EjecutorService , si el valor devuelto no es de mi interés?

Si pruebo ambos, no vi ninguna diferencia entre los dos, excepto el valor devuelto.

ExecutorService threadExecutor = Executors.newSingleThreadExecutor(); threadExecutor.execute(new Task());

ExecutorService threadExecutor = Executors.newSingleThreadExecutor(); threadExecutor.submit(new Task());


Existe una diferencia con respecto al manejo de excepciones / errores.

Una tarea puesta en cola con execute() que genera algo Throwable causará que se invoque UncaughtExceptionHandler para el Thread ejecuta la tarea. Se UncaughtExceptionHandler el UncaughtExceptionHandler predeterminado, que normalmente imprime el seguimiento de pila System.err a System.err , si no se ha instalado ningún controlador personalizado.

Por otro lado, un Throwable generado por una tarea en cola con submit() vinculará el Throwable to the Future que se produjo a partir de la llamada a submit() . Llamar a get() en ese Future arrojará una ExecutionException con el Throwable original como causa (accesible al llamar a getCause() en ExecutionException ).


La respuesta completa es una composición de dos respuestas que se publicaron aquí (más un poco "extra"):

  • Al enviar una tarea (en lugar de ejecutarla) obtiene un futuro que puede usarse para obtener el resultado o cancelar la acción. No tiene este tipo de control cuando execute (porque su tipo de retorno es void )
  • execute espera un Runnable mientras que submit puede tomar un Runnable o un Callable como argumento (para obtener más información acerca de la diferencia entre los dos, ver a continuación).
  • execute burbujas de cualquier excepción sin marcar de inmediato (¡no puede lanzar excepciones comprobadas!), mientras que submit vincula cualquier tipo de excepción al futuro que retorna como resultado, y solo cuando llama a future.get() a the (wrapped ) se lanzará una excepción. El Throwable que obtendrá es una instancia de ExecutionException y si llama a getCause() este objeto getCause() el getCause() original.

Algunos puntos más (relacionados):

  • Incluso si la tarea que desea submit no requiere la devolución de un resultado, aún puede usar Callable<Void> (en lugar de usar Runnable ).
  • La cancelación de tareas se puede hacer utilizando el mecanismo de interrupt . Aquí hay un ejemplo de cómo implementar una política de cancelación

En resumen, es una mejor práctica usar submit con un Callable (frente a execute con Runnable ). Y citaré "concurrencia de Java en la práctica" Por Brian Goetz:

6.3.2 Tareas que producen resultados: llamadas y futuro

El marco Executor usa Runnable como su representación de tarea básica. Runnable es una abstracción bastante limitante; ejecutar no puede devolver un valor ni arrojar excepciones controladas, aunque puede tener efectos secundarios, como escribir en un archivo de registro o colocar un resultado en una estructura de datos compartida. Muchas tareas son cálculos efectivamente diferidos: ejecución de una consulta de base de datos, búsqueda de un recurso en la red o cálculo de una función complicada. Para este tipo de tareas, Callable es una mejor abstracción: espera que el punto de entrada principal, llamada, devuelva un valor y anticipe que podría lanzar una excepción.7 Los ejecutores incluyen varios métodos de utilidad para ajustar otros tipos de tareas, incluyendo Runnable y java.security.PrivilegedAction, con un invocable.


Tomado del Javadoc:

El método de submit extiende el método base {@link Executor # execute } creando y devolviendo un {@link Future} que se puede usar para cancelar la ejecución y / o esperar a que se complete.

Personalmente prefiero el uso de execute porque se siente más declarativo, aunque esto realmente es una cuestión de preferencia personal.

Para obtener más información: en el caso de la implementación de ExecutorService , la implementación central devuelta por la llamada a Executors.newSingleThreadedExecutor() es un ThreadPoolExecutor .

Las llamadas de submit son provistas por su padre AbstractExecutorService y todas las llamadas se ejecutan internamente. ejecutar es reemplazado / provisto directamente por el ThreadPoolExecutor .


si no te importa el tipo de devolución, utiliza execute. es lo mismo que enviar, solo sin el regreso de Future.


ejecutar : usarlo para disparar y olvidar llamadas

enviar : Úselo para inspeccionar el resultado de la llamada al método y tomar las medidas adecuadas sobre el Future objetado devuelto por la llamada

De javadocs

submit(Callable<T> task)

Envía una tarea de devolución de valor para su ejecución y devuelve un futuro que representa los resultados pendientes de la tarea.

Future<?> submit(Runnable task)

Presenta una tarea ejecutable para su ejecución y devuelve un futuro que representa esa tarea.

void execute(Runnable command)

Ejecuta el comando dado en algún momento en el futuro. El comando puede ejecutarse en un nuevo hilo, en un hilo agrupado o en el hilo de llamada, a discreción de la implementación del Ejecutor.

Debe tener precaución al usar submit() . Oculta la excepción en el marco a menos que incruste su código de tarea en el bloque try{} catch{} .

Código de ejemplo: este código se traga la 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(); } }

salida:

java ExecuteSubmitDemo creating service a and b=4:0

El mismo código arroja reemplazando submit() con execute ():

Reemplazar

service.submit(new Runnable(){

con

service.execute(new Runnable(){

salida:

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)

¿Cómo manejar este tipo de escenarios al usar submit ()?

  1. Incruste su código de tarea ( implementación ejecutable o ejecutable) con try {} catch {} block code
  2. Implementar CustomThreadPoolExecutor

Nueva solución:

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); } }

salida:

java ExecuteSubmitDemo creating service a and b=4:0 java.lang.ArithmeticException: / by zero