¿Qué es un ExecutorService?

Para ser honesto, esta pregunta no es demasiado nueva. Han pasado más de 13 años desde el lanzamiento de Java 5 y el paquete java.util.concurrent. *, Pero en mis diez años de práctica, nunca he tenido que enfrentarme a esta bestia. Sin embargo, me hicieron esta pregunta varias veces durante las entrevistas y tuve que familiarizarme.



Naturalmente, lo primero con lo que comencé es Habr. Pero, desafortunadamente, solo encontré dos artículos aquí:



habrahabr.ru/post/260953

habrahabr.ru/post/116363



El primero, obviamente, para aquellos que entienden y tienen experiencia con ExecutorService. El segundo, lamentablemente, no me entró. Parece pequeño y "en el caso", pero después de releer varias veces todavía no entiendo qué es ExecutorService y con qué se come. Así que tuve que sentarme en Eclipse, fumar, leer javadoc y resolverlo.



Entonces, echemos un vistazo a un ejemplo simple:



ExecutorService service = Executors.newFixedThreadPool(3);
service.execute(new Runnable() {
    public void run() {
        System.out.println("Another thread was executed");
    }
});

      
      





En este ejemplo, creamos el objeto ExecutorService en sí y llamamos al método de ejecución en él. Pasándole la implementación de hilo más común. Todo esto podría haberse construido a la manera del viejo abuelo, pero esto, como ve, es mucho más simple y elegante. De hecho, ramificamos rápidamente otro subproceso asincrónico del subproceso actual, que puede hacer algo allí en segundo plano.

Creamos el objeto ExecutorService usando una fábrica. Sus métodos son bastante obvios, por lo que no seremos demasiado procrastinados. Éstos son algunos de ellos:



ExecutorService service1 = Executors.newSingleThreadExecutor();
ExecutorService service2 = Executors.newFixedThreadPool(3);
ExecutorService service3 = Executors.newScheduledThreadPool(3);

      
      





Además del método de ejecución, que se llama según el principio de "disparar y olvidar", nuestro servicio también tiene un método de envío. La única diferencia con el primero es que el segundo devuelve un objeto de la interfaz Future. Esta es solo una excelente manera de controlar el estado del hilo que ejecutamos en segundo plano. Se hace algo como esto:



Future future = service.submit(new Runnable() {
    public void run() {
        System.out.println("Another thread was executed");
    }
});
...
future.get();

      
      





Tenga en cuenta que el método get bloqueará mortalmente el hilo actual y esperará hasta que finalice el hilo en segundo plano. ¡Ahora no necesitas todas estas uniones no obvias! Si tenemos miedo de que nuestro hilo de fondo nunca termine, podemos usar get (long, TimeUnit).



A veces tienes que devolver datos de un hilo en segundo plano al actual. El método de envío también nos ayudará con esto, pero ahora necesitamos pasarle no un objeto Runnable, sino un objeto invocable. De hecho, estas son dos interfaces idénticas, la única diferencia es que esta última puede devolver algo:



Future future = service.submit(new Callable(){
    public Object call() throws Exception {
        System.out.println("Another thread was executed");
        return "result";
    }
});
...
System.out.println("Result: " + future.get());

      
      





Bueno, en resumen, eso es todo. Fueron métodos de crear ExecutorService -y en la fábrica (que hay muchos), fueron los métodos del ExecutorService, problemas de manejo de errores en un hilo de fondo, pero esa es otra historia ...



Al final de no te olvides de:



servcie.shutdown();

      
      





O no, si todos los subprocesos en segundo plano son demonios.



All Articles