Tengo un requisito para que una tarea se ejecute de forma asincrónica, descartando cualquier solicitud adicional hasta que la tarea finalice.Enhebrado sencillo de una tarea sin encolamiento de solicitudes adicionales
Sincronizando el método, solo pone en cola las tareas y no omite. Inicialmente pensé usar un SingleThreadExecutor pero eso también pone en cola tareas. Luego miré al ThreadPoolExecutor pero se lee la cola para ejecutar la tarea y, por lo tanto, se ejecutará una tarea y se pondrá en cola al menos una tarea (las otras se pueden descartar usando ThreadPoolExecutor.DiscardPolicy).
Lo único que puedo pensar es utilizar un semáforo para bloquear la cola. He venido con el siguiente ejemplo para mostrar lo que estoy tratando de lograr. ¿Hay alguna forma más simple? ¿Me he perdido algo obvio?
import java.util.concurrent.*;
public class ThreadPoolTester {
private static ExecutorService executor = Executors.newSingleThreadExecutor();
private static Semaphore processEntry = new Semaphore(1);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 20; i++) {
kickOffEntry(i);
Thread.sleep(200);
}
executor.shutdown();
}
private static void kickOffEntry(final int index) {
if (!processEntry.tryAcquire()) return;
executor.
submit(
new Callable<Void>() {
public Void call() throws InterruptedException {
try {
System.out.println("start " + index);
Thread.sleep(1000); // pretend to do work
System.out.println("stop " + index);
return null;
} finally {
processEntry.release();
}
}
}
);
}
}
Ejemplo de salida
start 0
stop 0
start 5
stop 5
start 10
stop 10
start 15
stop 15
Tomando la respuesta de axtavt y transformando el ejemplo anterior dicta la siguiente solución más simple.
import java.util.concurrent.*;
public class SyncQueueTester {
private static ExecutorService executor = new ThreadPoolExecutor(1, 1,
1000, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadPoolExecutor.DiscardPolicy());
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 20; i++) {
kickOffEntry(i);
Thread.sleep(200);
}
executor.shutdown();
}
private static void kickOffEntry(final int index) {
executor.
submit(
new Callable<Void>() {
public Void call() throws InterruptedException {
System.out.println("start " + index);
Thread.sleep(1000); // pretend to do work
System.out.println("stop " + index);
return null;
}
}
);
}
}
desvivían usted me dice, ¿por qué prefiere utilizar una ¿DiscardPolicy sobre la captura de RejectedExecutionException? –