Defina uma interface de retorno de chamada para receber os parâmetros que você deseja transmitir na notificação de conclusão. Em seguida, invoque-o no final da tarefa.
Você pode até escrever um wrapper geral para tarefas Runnable e enviá-las para ExecutorService
. Ou veja abaixo um mecanismo incorporado ao Java 8.
class CallbackTask implements Runnable {
private final Runnable task;
private final Callback callback;
CallbackTask(Runnable task, Callback callback) {
this.task = task;
this.callback = callback;
}
public void run() {
task.run();
callback.complete();
}
}
Com CompletableFuture
, o Java 8 incluiu um meio mais elaborado de compor pipelines onde os processos podem ser concluídos de forma assíncrona e condicional. Aqui está um exemplo completo, mas completo, de notificação.
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class GetTaskNotificationWithoutBlocking {
public static void main(String... argv) throws Exception {
ExampleService svc = new ExampleService();
GetTaskNotificationWithoutBlocking listener = new GetTaskNotificationWithoutBlocking();
CompletableFuture<String> f = CompletableFuture.supplyAsync(svc::work);
f.thenAccept(listener::notify);
System.out.println("Exiting main()");
}
void notify(String msg) {
System.out.println("Received message: " + msg);
}
}
class ExampleService {
String work() {
sleep(7000, TimeUnit.MILLISECONDS); /* Pretend to be busy... */
char[] str = new char[5];
ThreadLocalRandom current = ThreadLocalRandom.current();
for (int idx = 0; idx < str.length; ++idx)
str[idx] = (char) ('A' + current.nextInt(26));
String msg = new String(str);
System.out.println("Generated message: " + msg);
return msg;
}
public static void sleep(long average, TimeUnit unit) {
String name = Thread.currentThread().getName();
long timeout = Math.min(exponential(average), Math.multiplyExact(10, average));
System.out.printf("%s sleeping %d %s...%n", name, timeout, unit);
try {
unit.sleep(timeout);
System.out.println(name + " awoke.");
} catch (InterruptedException abort) {
Thread.currentThread().interrupt();
System.out.println(name + " interrupted.");
}
}
public static long exponential(long avg) {
return (long) (avg * -Math.log(1 - ThreadLocalRandom.current().nextDouble()));
}
}
Callback
interface que você declara; não de uma biblioteca. Hoje em dia eu provavelmente usariaRunnable
,Consumer
ouBiConsumer
, dependendo do que preciso passar da tarefa para o ouvinte.No Java 8, você pode usar o CompletableFuture . Aqui está um exemplo que eu tive no meu código em que estou usando-o para buscar usuários do meu serviço de usuário, mapeá-los para meus objetos de exibição e atualizar minha exibição ou mostrar uma caixa de diálogo de erro (este é um aplicativo GUI):
Ele é executado de forma assíncrona. Estou usando dois métodos particulares:
mapUsersToUserViews
eupdateView
.fonte
Use a futura API escutável do Guava e adicione um retorno de chamada. Cf. a partir do site :
fonte
Você pode estender a
FutureTask
classe e substituir odone()
método e, em seguida, adicionar oFutureTask
objeto aoExecutorService
, para que odone()
método seja chamado quandoFutureTask
concluído imediatamente.fonte
then add the FutureTask object to the ExecutorService
, poderia me dizer como fazer isso?ThreadPoolExecutor
também possui métodos hookbeforeExecute
eafterExecute
que você pode substituir e usar. Aqui está a descriçãoThreadPoolExecutor
dos Javadocs de .fonte
Use a
CountDownLatch
.É de
java.util.concurrent
e é exatamente o caminho de aguardar vários threads para concluir a execução antes de continuar.Para obter o efeito de retorno de chamada que você está cuidando, isso exige um pouco de trabalho extra adicional. Ou seja, lidar com isso sozinho em um thread separado que usa
CountDownLatch
e espera, e depois avisa o que você precisa notificar. Não há suporte nativo para retorno de chamada ou algo semelhante a esse efeito.EDIT: agora que entendi melhor sua pergunta, acho que você está chegando longe demais, desnecessariamente. Se você fizer um regular
SingleThreadExecutor
, execute todas as tarefas e ele fará as filas de forma nativa.fonte
Se você deseja garantir que nenhuma tarefa seja executada ao mesmo tempo, use um SingleThreadedExecutor . As tarefas serão processadas na ordem em que são enviadas. Você nem precisa realizar as tarefas, basta enviá-las ao executivo.
fonte
Código simples para implementar
Callback
mecanismo usandoExecutorService
resultado:
Notas principais:
newFixedThreadPool(5)
pornewFixedThreadPool(1)
Se você deseja processar a próxima tarefa depois de analisar o resultado
callback
da tarefa anterior, basta desmarcar a linha abaixoVocê pode substituir
newFixedThreadPool()
por um dosdependendo do seu caso de uso.
Se você deseja manipular o método de retorno de chamada de forma assíncrona
uma. Passar uma
ExecutorService or ThreadPoolExecutor
tarefa compartilhada para Callableb. Converta seu
Callable
método emCallable/Runnable
tarefac. Envie a tarefa de retorno de chamada para
ExecutorService or ThreadPoolExecutor
fonte
Apenas para adicionar à resposta de Matt, que ajudou, aqui está um exemplo mais detalhado para mostrar o uso de um retorno de chamada.
A saída é:
fonte
Você pode usar uma implementação de Callable de forma que
onde CallbackInterface é algo muito básico como
e agora a classe principal ficará assim
fonte
Esta é uma extensão da resposta do Pache usando goiabas
ListenableFuture
.Em particular, os
Futures.transform()
retornosListenableFuture
podem ser usados para encadear chamadas assíncronas.Futures.addCallback()
retornavoid
, portanto, não pode ser usado para encadeamento, mas é bom para lidar com sucesso / falha em uma conclusão assíncrona.NOTA: Além de encadear tarefas assíncronas,
Futures.transform()
também permite agendar cada tarefa em um executor separado (não mostrado neste exemplo).fonte