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()));
}
}
Callback
interfaz que declaras; No de una biblioteca. Hoy en día, probablemente solo usaríaRunnable
,Consumer
oBiConsumer
, 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:
mapUsersToUserViews
yupdateView
.fuente
Use la futura API escuchable de Guava y agregue una devolución de llamada. Cf. del sitio web:
fuente
Puede extender la
FutureTask
clase y anular eldone()
método, luego agregar elFutureTask
objeto alExecutorService
, para que eldone()
método invoque cuando seFutureTask
complete de inmediato.fuente
then add the FutureTask object to the ExecutorService
, ¿podría decirme cómo hacer esto?ThreadPoolExecutor
También tienebeforeExecute
yafterExecute
métodos de enlace que pueden anular y hacer uso de. Aquí está la descripción deThreadPoolExecutor
los Javadocs de .fuente
Usar una
CountDownLatch
.Es de
java.util.concurrent
y 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
CountDownLatch
y 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
Callback
mecanismo usandoExecutorService
salida:
Notas clave:
newFixedThreadPool(5)
connewFixedThreadPool(1)
Si desea procesar la siguiente tarea después de analizar el resultado
callback
de 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 ThreadPoolExecutor
tarea a invocablesi. Convierte tu
Callable
método aCallable/Runnable
tareaC. Empuje la tarea de devolución de llamada a
ExecutorService or ThreadPoolExecutor
fuente
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()
retornosListenableFuture
pueden 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