O Java ExecutorService é a interface que nos permite executar tarefas em threads de forma assíncrona. A interface Java ExecutorService está presente no pacote java.util.concurrent. O ExecutorService ajuda a manter um pool de threads e atribui tarefas a eles. Ele também fornece a facilidade de enfileirar tarefas até que haja um thread livre disponível se o número de tarefas for maior que o número de threads disponíveis.
Métodos de Java ExecutorService
Método | Descrição |
---|---|
boolean waitTermination(tempo limite longo, unidade TimeUnit) | Este método bloqueia a tarefa para entrar no ExecutorService até que todas as tarefas sejam concluídas após a solicitação de desligamento, ou o tempo limite determinado ocorra, ou o thread atual seja interrompido, o que acontecer primeiro. |
Lista | Este método executa a lista de tarefas fornecidas e retorna a lista de Futuros que contém os resultados de todas as tarefas quando concluídas. |
Lista | Este método executa a lista de tarefas fornecidas e retorna a lista de Futuros que contém os resultados de todas as tarefas quando concluídas ou quando o tempo limite expirar, o que ocorrer primeiro. |
T invocaAny(Coleção extends Callable>tarefas) | Este método executa a lista de tarefas fornecidas e retorna o resultado de uma tarefa que é concluída sem gerar nenhuma exceção. |
T invocaAny(Coleção extends Callable>tarefas, tempo limite longo, unidade TimeUnit) | Este método executa a lista de tarefas fornecidas e retorna o resultado de uma tarefa que é concluída sem lançar nenhuma exceção antes que o tempo limite termine. |
booleano éShutdown() | Este método retorna se o executor fornecido está desligado ou não. |
booleano éTerminado() | Este método retorna verdadeiro se todas as tarefas foram executadas após o desligamento. |
desligamento vazio() | Este método permite a conclusão de tarefas previamente enviadas ao ExecutorService e não permite a aceitação de nenhuma outra tarefa. |
Lista shutdownNow() | Este método interrompe todas as tarefas em execução ativa, interrompe a execução de tarefas enfileiradas e retorna a lista de tarefas enfileiradas. |
Envio futuro (tarefa chamável) | Este método envia uma tarefa que retorna valor para execução e retorna o Future, que representa o resultado pendente da tarefa. |
Envio futuro (tarefa executável) | Este método envia uma tarefa para execução e retorna um Future representando essa tarefa. Ele retorna nulo após a conclusão bem-sucedida. |
Envio futuro (tarefa executável, resultado T) | Este método envia uma tarefa para execução e retorna um Future representando essa tarefa. |
Um programa simples 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(); } }
Saída:
Neste programa, estamos criando um ExecutorService com dez threads e atribuindo a ele uma implementação executável anônima que executa uma tarefa para imprimir 'ExecutorService' e após o término de sua tarefa, estamos desligando o serviço executor.
Como usar Java ExecutorService
Instanciando ExecutorService
Podemos usar Java ExecutorService para criar um único encadeamento, um conjunto de encadeamentos ou um conjunto agendado de encadeamentos. A classe Executors fornece métodos de fábrica para instanciar um ExecutorService da seguinte forma:
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.
Atribuindo tarefas ao ExecutorServices
Para atribuir uma tarefa ao ExecutorService, podemos usar os seguintes métodos-
- executar (tarefa executável)
- submit(tarefa executável) / submit(tarefa chamável)
- invocarAny(Coleção extends Callable>tarefas)
- invocarAll(Coleção extends Callable>tarefas)
Exemplo de atribuição de uma tarefa ao ExecutorService usando o método execute()
O método execute() do Java ExecutorService recebe um objeto executável e executa sua tarefa de forma assíncrona. Após fazer a chamada ao método execute, chamamos o método shutdown, que bloqueia qualquer outra tarefa para enfileirar-se no 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(); } }
Saída:
ExecutorService
Exemplo de atribuição de uma tarefa ao ExecutorService usando submit()
O método submit() recebe um objeto executável e retorna um objeto Future. Este objeto é posteriormente usado para verificar o status do Runnable, independentemente de ele ter concluído a execução ou não.
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'); } }); } }
Exemplo de atribuição de uma tarefa ao ExecutorService usando o método InvokeAny()
O método InvokeAny() pega uma coleção de objetos Callablle ou objetos de classes que implementam Callable. Este método retorna o objeto futuro do objeto que pode ser chamado que é executado primeiro com sucesso.
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>
Saída:
result = Task 1
O resultado armazena a Tarefa 1 quando o primeiro objeto que pode ser chamado é executado primeiro com êxito.
Exemplo de atribuição de uma tarefa ao ExecutorService usando o método InvokeAll()
O método invocaAll() recebe uma coleção de objetos que podem ser chamados com tarefas e retorna uma lista de objetos Future contendo o resultado de todas as tarefas.
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>
Saída:
future.get = Task 1 future.get = Task 3 future.get = Task 2
Como desligar o ExecutorService
Assim que terminarmos nossas tarefas atribuídas ao ExecutorService, teremos que encerrá-lo porque o ExecutorService executa a tarefa em threads diferentes. Se não encerrarmos o ExecutorService, os threads continuarão em execução e a JVM não será encerrada.
O processo de desligamento pode ser feito pelos três métodos a seguir:
- método shutdown()
- método shutdownNow()
- Método waitTermination()