La diferencia entre Executor, ExecutorService y Executors (transferencia)

Fuente original: http://www.importnew.com/24923.html

java.util.concurrent.Executor, java.util.concurrent.ExecutorService, java.util.concurrent.Ejecutores Estos tres son todos parte del marco Java Executor y se utilizan para proporcionar funciones de grupo de subprocesos. Debido a que crear y administrar subprocesos es muy agotador, y el sistema operativo generalmente limita la cantidad de subprocesos, se recomienda usar grupos de subprocesos para realizar tareas al mismo tiempo en lugar de crear un subproceso cada vez que ingresa una solicitud. El uso del grupo de subprocesos no solo puede mejorar el tiempo de respuesta de la aplicación, sino también evitar errores como "java.lang.OutOfMemoryError: no se puede crear un nuevo subproceso nativo".

En Java 1.5, los desarrolladores deben preocuparse por la creación y administración de grupos de subprocesos, pero después de Java 1.5, el marco Executor proporciona una variedad de grupos de subprocesos integrados, por ejemplo: FixedThreadPool (contiene un número fijo de subprocesos), CachedThreadPool (puede crear nuevos según sea necesario Hilo) y así sucesivamente.

Ejecutor

La principal diferencia entre Executor, ExecutorService y Executors es que Executor es una interfaz central abstracta (el código aproximado es el siguiente).

public interface Executor {
    void execute(Runnable command);
}

A diferencia de la clase java.lang.Thread que combina tareas y ejecución, Executor separa la tarea en sí de la tarea de ejecución. Puedes leer Diferencia entre Thread y Executor para aprender más sobre las diferencias entre Thread y Executor.

ExecutorService

La interfaz ExecutorService amplía la interfaz Executor y proporciona métodos para devolver el objeto Future, finalizar y cerrar el grupo de subprocesos. Cuando se llama al método shutDown, el grupo de subprocesos dejará de aceptar nuevas tareas, pero completará las tareas pendientes.

El objeto Future proporciona una ejecución asincrónica, lo que significa que no es necesario esperar a que se complete la ejecución de la tarea. Simplemente envíe la tarea que debe ejecutarse y luego verifique si el Future tiene un resultado cuando sea necesario. Si la tarea se ejecutó, puede usar Future.get () El método obtiene el resultado de la ejecución. Cabe señalar que el método Future.get () es un método de bloqueo. Si la tarea no se completa cuando se llama, esperará hasta que finalice la ejecución de la tarea.

La ejecución de la tarea también se puede cancelar a través del objeto Future devuelto por el método ExecutorService.submit (). Future proporciona el método cancel () para cancelar la ejecución de tareas pendientes.

Parte del código de ExecutorService es el siguiente:

public interface ExecutorService extends Executor {
    void shutdown();
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
}

Ejecutores

Executors es una clase de herramienta, similar a Colecciones. Proporcione métodos de fábrica para crear diferentes tipos de grupos de subprocesos, como FixedThreadPool o CachedThreadPool.

Ejecutores parte del código:

public class Executors {
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
        }
         
     public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        }
}

Echemos un vistazo a las diferencias entre los tres en detalle:

Ejecutor vs Ejecutor Servicio vs Ejecutores

Como se mencionó anteriormente, estos tres son parte del marco del Ejecutor. Es necesario que los desarrolladores de Java los aprendan y comprendan para poder utilizar los diferentes tipos de grupos de subprocesos proporcionados por Java de manera más eficiente. Resuma las diferencias entre estos tres para que todos puedan comprender mejor:

  • La principal diferencia entre las interfaces Executor y ExecutorService es que la interfaz ExecutorService hereda la interfaz Executor y es una subinterfaz de Executor
  • La segunda diferencia entre Executor y ExecutorService es que la interfaz Executor define el método execute () para recibir un objeto de interfaz Runnable, mientras que el método submit () en la interfaz ExecutorService puede aceptar objetos de interfaz Runnable y Callable.
  • La tercera diferencia entre las interfaces Executor y ExecutorService es que el método execute () en Executor no devuelve ningún resultado, mientras que el método submit () en ExecutorService puede devolver el resultado de la operación a través de un objeto Future.
  • La cuarta diferencia entre las interfaces Executor y ExecutorService es que, además de permitir que el cliente envíe una tarea, ExecutorService también proporciona métodos para controlar el grupo de subprocesos. Por ejemplo: llame al método shutDown () para terminar el grupo de subprocesos. Puede obtener más información sobre cómo cerrar el grupo de subprocesos y cómo manejar las tareas pendientes a través del libro " Concurrencia de Java en la práctica ".
  • La clase Executors proporciona métodos de fábrica para crear diferentes tipos de grupos de subprocesos. Por ejemplo: newSingleThreadExecutor () crea un grupo de subprocesos con solo un subproceso, newFixedThreadPool (int numOfThreads) crea un grupo de subprocesos con un número fijo de subprocesos, newCachedThreadPool () puede crear nuevos subprocesos según sea necesario, pero si los subprocesos existentes están inactivos, se reutilizarán. Hay hilos.

para resumir

La siguiente tabla enumera la diferencia entre Executor y ExecutorService:

Nota del traductor

Personalmente, creo que es muy conveniente utilizar el método de fábrica proporcionado por la clase Executors para crear un grupo de subprocesos, pero no es adecuado para escenarios donde algunos parámetros del grupo de subprocesos deben personalizarse de acuerdo con la situación real.

Por ejemplo:
cuando los subprocesos en el grupo de subprocesos están en un estado de trabajo, y el número de subprocesos ha alcanzado el número máximo de subprocesos permitido por el grupo de subprocesos, se adoptará la estrategia de saturación especificada para procesar las tareas recién enviadas. Hay cuatro estrategias en total:

  • AbortPolicy: lanzar la excepción directamente
  • CallerRunsPolicy: usa el hilo de la persona que llama para ejecutar tareas
  • DiscardOldestPolicy: descarte la tarea más reciente en la cola de subprocesos y ejecute la tarea recién enviada
  • DiscardPolicy descarta directamente nuevas tareas

Si usa el grupo de subprocesos creado por el método de fábrica de Executors, la estrategia de saturación es la AbortPolicy predeterminada, por lo que si queremos usar el subproceso del llamador para ejecutar la tarea cuando el grupo de subprocesos está lleno, debemos crear el grupo de subprocesos nosotros mismos y especificar Quiere la estrategia de saturación en lugar de utilizar más ejecutores.

Entonces podemos crear un objeto ThreadPoolExecutor (clase de implementación de la interfaz ExecutorService) y personalizar algunos parámetros en lugar de llamar al método de fábrica de Executors.

Por supuesto, en proyectos que usan el marco de Spring, también puede usar la clase ThreadPoolTaskExecutor proporcionada por Spring para crear un grupo de subprocesos. Similar a ThreadPoolExecutor, ThreadPoolTaskExecutor también proporciona muchos parámetros para personalizar el grupo de subprocesos, como: tamaño del grupo de subprocesos central, número máximo de grupos de subprocesos, estrategia de saturación, tiempo de retención de actividad de subprocesos, etc.

Supongo que te gusta

Origin blog.csdn.net/u013821237/article/details/89553610
Recomendado
Clasificación