Defina una interfaz de devolución de llamada para recibir los parámetros que desee transmitir en la notificación de finalización. Luego invoque al final de la tarea.
Incluso podría escribir un contenedor general para tareas Runnable y enviarlas a ExecutorService. O vea a continuación un mecanismo integrado en 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();
}
}
Con CompletableFuture, Java 8 incluyó un medio más elaborado para componer tuberías donde los procesos se pueden completar de forma asincrónica y condicional. Aquí hay un ejemplo artificial pero completo de notificación.
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()));
}
}
Callbackinterfaz que declaras; No de una biblioteca. Hoy en día, probablemente solo usaríaRunnable,ConsumeroBiConsumer, dependiendo de lo que necesite pasar de la tarea al oyente.En Java 8 puedes usar CompletableFuture . Aquí hay un ejemplo que tenía en mi código donde lo estoy usando para buscar usuarios de mi servicio de usuario, asignarlos a mis objetos de vista y luego actualizar mi vista o mostrar un diálogo de error (esta es una aplicación GUI):
Se ejecuta de forma asincrónica. Estoy usando dos métodos privados:
mapUsersToUserViewsyupdateView.fuente
Use la futura API escuchable de Guava y agregue una devolución de llamada. Cf. del sitio web:
fuente
Puede extender la
FutureTaskclase y anular eldone()método, luego agregar elFutureTaskobjeto alExecutorService, para que eldone()método invoque cuando seFutureTaskcomplete de inmediato.fuente
then add the FutureTask object to the ExecutorService, ¿podría decirme cómo hacer esto?ThreadPoolExecutorTambién tienebeforeExecuteyafterExecutemétodos de enlace que pueden anular y hacer uso de. Aquí está la descripción deThreadPoolExecutorlos Javadocs de .fuente
Usar una
CountDownLatch.Es de
java.util.concurrenty es exactamente la forma de esperar que varios hilos completen la ejecución antes de continuar.Para lograr el efecto de devolución de llamada que está buscando, eso requiere un poco de trabajo adicional adicional. Es decir, manejar esto usted mismo en un hilo separado que usa
CountDownLatchy espera, luego continúa notificando lo que sea que necesite notificar. No hay soporte nativo para la devolución de llamada, ni nada similar a ese efecto.EDITAR: ahora que entiendo mejor tu pregunta, creo que estás llegando demasiado lejos, innecesariamente. Si toma una rutina
SingleThreadExecutor, dele todas las tareas y hará la cola de forma nativa.fuente
Si desea asegurarse de que no se ejecutarán tareas al mismo tiempo, utilice un SingleThreadedExecutor . Las tareas se procesarán en el orden en que se envían. Ni siquiera necesita retener las tareas, solo envíelas al ejecutivo.
fuente
Código simple para implementar
Callbackmecanismo usandoExecutorServicesalida:
Notas clave:
newFixedThreadPool(5)connewFixedThreadPool(1)Si desea procesar la siguiente tarea después de analizar el resultado
callbackde la tarea anterior, simplemente descomente debajo de la líneaPuedes reemplazar
newFixedThreadPool()con uno dedependiendo de su caso de uso.
Si desea manejar el método de devolución de llamada de forma asincrónica
a. Pase un compartido
ExecutorService or ThreadPoolExecutortarea a invocablesi. Convierte tu
Callablemétodo aCallable/RunnabletareaC. Empuje la tarea de devolución de llamada a
ExecutorService or ThreadPoolExecutorfuente
Solo para agregar a la respuesta de Matt, que ayudó, aquí hay un ejemplo más detallado para mostrar el uso de una devolución de llamada.
El resultado es:
fuente
Puede usar una implementación de Callable de modo que
donde CallbackInterface es algo muy básico como
y ahora la clase principal se verá así
fuente
Esta es una extensión de la respuesta de Pache usando la guayaba
ListenableFuture.En particular, los
Futures.transform()retornosListenableFuturepueden usarse para encadenar llamadas asíncronas.Futures.addCallback()devuelvevoid, por lo que no se puede usar para encadenar, pero es bueno para manejar el éxito / fracaso en una finalización asíncrona.NOTA: Además de encadenar tareas asíncronas,
Futures.transform()también le permite programar cada tarea en un ejecutor separado (no se muestra en este ejemplo).fuente