El Java ExecutorService és la interfície que ens permet executar tasques en fils de manera asíncrona. La interfície Java ExecutorService està present al paquet java.util.concurrent. L'ExecutorService ajuda a mantenir un conjunt de fils i els assigna tasques. També ofereix la possibilitat de posar en cua les tasques fins que hi hagi un fil lliure disponible si el nombre de tasques és superior als fils disponibles.
Mètodes de Java ExecutorService
Mètode | Descripció |
---|---|
booleà awaitTermination (temps d'espera llarg, unitat TimeUnit) | Aquest mètode bloqueja la tasca per entrar a ExecutorService fins que s'hagin completat totes les tasques després de la sol·licitud d'apagada, o es produeixi el temps d'espera donat o s'interrompi el fil actual, el que passi primer. |
Llista | Aquest mètode executa la llista de tasques donades i retorna la llista de futurs que conté els resultats de totes les tasques quan s'han completat. |
Llista | Aquest mètode executa la llista de tasques donades i retorna la llista de futurs que conté els resultats de totes les tasques quan s'han completat o el temps d'espera expira, el que passi primer. |
T invokeAny(Col·lecció extends Callable>tasques) | Aquest mètode executa la llista de tasques donades i retorna el resultat d'una tasca que es completa sense llançar cap excepció. |
T invokeAny(Col·lecció extends Callable>tasques, temps d'espera llarg, unitat TimeUnit) | Aquest mètode executa la llista de tasques donades i retorna el resultat d'una tasca que es completa sense llançar cap excepció abans que transcorri el temps d'espera. |
booleà isShutdown() | Aquest mètode retorna si l'executor donat està tancat o no. |
booleà està acabat () | Aquest mètode retorna true si totes les tasques s'han executat després de l'apagada. |
anul·la l'aturada () | Aquest mètode permet completar tasques enviades prèviament a l'ExecutorService i no permet acceptar cap altra tasca. |
Llista shutdownNow() | Aquest mètode atura totes les tasques en execució activa, atura l'execució de les tasques a la cua i retorna la llista de tasques que estan a la cua. |
Enviament futur (tasca que es pot cridar) | Aquest mètode envia una tasca de retorn de valor per a l'execució i retorna el futur, que representa el resultat pendent de la tasca. |
Enviament futur (tasca executable) | Aquest mètode envia una tasca per a l'execució i retorna un futur que representa aquesta tasca. Torna nul en finalitzar correctament. |
Enviament futur (tasca executable, resultat T) | Aquest mètode envia una tasca per a l'execució i retorna un futur que representa aquesta tasca. |
Un programa senzill de Java ExecutorService
public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new Runnable() { @Override public void run() { System.out.println('ExecutorService'); } }); executorService.shutdown(); } }
Sortida:
En aquest programa, estem creant un ExecutorService amb deu fils i assignant-li una implementació executable anònima que realitza una tasca per imprimir 'ExecutorService' i un cop finalitzada la seva tasca, tanquem el servei executor.
Com utilitzar Java ExecutorService
Instanciació d'ExecutorService
Podem utilitzar Java ExecutorService per crear un únic fil, un grup de fils o un grup de fils programat. La classe Executors proporciona mètodes de fàbrica per crear una instancia d'un ExecutorService de la següent manera:
ExecutorService executorService1 = Executors.newSingleThreadExecutor(); //Creates //a ExecutorService object having a single thread. ExecutorService executorService2 = Executors.newFixedThreadPool(10); // Creates a //ExecutorService object having a pool of 10 threads. ExecutorService executorService3 = Executors.newScheduledThreadPool(10); //Creates a scheduled thread pool executor with 10 threads. In scheduled thread //pool, we can schedule tasks of the threads.
Assignació de tasques a ExecutorServices
Per assignar una tasca a ExecutorService, podem utilitzar els mètodes següents:
- executar (tasca executable)
- enviar (tasca que es pot executar) / enviar (tasca que es pot cridar)
- invokeAny(Col·lecció extends Callable>tasques)
- invokeAll(Col·lecció extends Callable>tasques)
Exemple d'assignació d'una tasca a ExecutorService mitjançant el mètode execute().
El mètode execute() del Java ExecutorService incorpora un objecte executable i realitza la seva tasca de manera asíncrona. Després de fer la crida al mètode d'execució, anomenem el mètode d'apagada, que bloqueja qualsevol altra tasca per posar en cua a executorService.
public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Runnable() { @Override public void run() { System.out.println('ExecutorService'); } }); executorService.shutdown(); } }
Sortida:
ExecutorService
Exemple d'assignació d'una tasca a ExecutorService mitjançant submit()
El mètode submit() agafa un objecte executable i retorna un objecte Future. Aquest objecte s'utilitza més tard per comprovar l'estat de Runnable si s'ha completat l'execució o no.
public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(new Runnable() { @Override public void run() { System.out.println('ExecutorService'); } }); } }
Exemple d'assignació d'una tasca a ExecutorService mitjançant el mètode invokeAny().
El mètode invokeAny() pren una col·lecció d'objectes Callablle o objectes de classes que implementen Callable. Aquest mètode retorna l'objecte futur de l'objecte cridable que s'executa amb èxit primer.
public class ExecutorServiceExample { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<callable> callables = new HashSet<callable>(); callables.add(new Callable() { public String call() throws Exception { return 'Task 1'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 2'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 3'; } }); String result = executorService.invokeAny(callables); System.out.println('result = ' + result); executorService.shutdown(); } } </callable></callable>
Sortida:
result = Task 1
El resultat emmagatzema la tasca 1 ja que primer s'executa correctament el primer objecte cridable.
Exemple d'assignació d'una tasca a ExecutorService mitjançant el mètode invokeAll().
El mètode invokeAll() recull una col·lecció d'objectes cridables amb tasques i retorna una llista d'objectes futurs que conté el resultat de totes les tasques.
public class ExecutorServiceExample { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<callable> callables = new HashSet<callable>(); callables.add(new Callable() { public String call() throws Exception { return 'Task 1'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 2'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 3'; } }); java.util.List<future> futures = executorService.invokeAll(callables); for(Future future : futures){ System.out.println('future.get = ' + future.get()); } executorService.shutdown(); } } </future></callable></callable>
Sortida:
future.get = Task 1 future.get = Task 3 future.get = Task 2
Com tancar l'ExecutorService
Un cop acabem amb les nostres tasques assignades a ExecutorService, haurem de tancar-lo perquè ExecutorService realitza la tasca en diferents fils. Si no tanquem l'ExecutorService, els fils continuaran funcionant i la JVM no s'aturarà.
El procés de tancament es pot fer mitjançant els tres mètodes següents:
- mètode shutdown().
- mètode shutdownNow().
- Mètode awaitTermination().