java - tiempo - timertask android ejemplo
Detenga una tarea periódica desde la misma tarea que se ejecuta en un ScheduledExecutorService (5)
Acabo de ver esto ahora ... porque quería hacer lo mismo ... aquí está mi solución, sospecho que esto es seguro para hilos.
Primero crea un contenedor para el futuro:
public static class Cancel {
private ScheduledFuture<?> future;
public synchronized void setFuture(ScheduledFuture<?> future) {
this.future = future;
}
public synchronized void stop() {
LOG.debug("cancelling {}", future);
future.cancel(false);
}
}
Y luego el código futuro:
final Cancel controller = new Cancel();
synchronized (controller) {
ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay(() -> {
if (<CONTINUE RUNNING CONDITION) {
} else {
// STOP SCHEDULABLE FUTURE
controller.stop();
}
}, startTime, timeBetweenVisbilityChecks);
controller.setFuture(future);
}
}
Por lo tanto, tenga en cuenta que la parada no se podrá cancelar hasta que se haya creado el futuro y se haya establecido el futuro en el controlador.
Tenga en cuenta que el Runnable es la clase interna anomima y esto se ejecutará en un hilo diferente por completo.
¿Hay una buena manera de detener la repetición de tareas desde la misma tarea cuando se ejecuta en un ScheduledExecutorService?
Digamos, tengo la siguiente tarea:
Future<?> f = scheduledExecutor.scheduleAtFixedRate(new Runnable() {
int count = 0;
public void run() {
System.out.println(count++);
if (count == 10) {
// ??? cancel self
}
}
}, 1, 1, TimeUnit.SECONDS);
Desde el exterior, es fácil de cancelar a través de f.cancel (), pero ¿cómo puedo detener la repetición en el lugar especificado? (Pasar el futuro a través de una referencia atómica no es seguro, ya que existe una ventana potencial cuando la fecha de la programación se devuelve con retraso y la variable también se establece con retraso, y es posible que la tarea ya se ejecute, al ver un nulo en la referencia).
Aquí hay otra forma, incluso Thread safe;
final Future<?>[] f = {null};
f[0]= scheduledExecutor.scheduleAtFixedRate(new Runnable() {
int count = 0;
public void run() {
System.out.println(count++);
if (count == 10) {
Future<?> future;
while(null==(future = f[0])) Thread.yield();//prevent exceptionally bad thread scheduling
future.cancel(false);
return;
//cancel self
}
}
}, 1, 1, TimeUnit.SECONDS);
Cuando una tarea repetitiva lanza una excepción o error, se coloca en el futuro y la tarea no se repite nuevamente. Puede lanzar una excepción RuntimeException o un error de su elección.
En lugar de usar una clase interna anónima, puede usar una clase con nombre que luego puede tener una propiedad para el objeto Future
que obtiene del Executor
cuando programa una tarea.
abstract class FutureRunnable implements Runnable {
private Future<?> future;
/* Getter and Setter for future */
}
Cuando programa una tarea, puede pasar el Future
a Runnable
.
FutureRunnable runnable = new FutureRunnable() {
public void run() {
if (/* abort condition */)
getFuture().cancel(false);
}
};
Future<?> future = executor.scheduleAtFixedRate(runnable, ...);
runnable.setFuture(future);
Tal vez tendrá que asegurarse de que la tarea no se ejecute antes de que se haya configurado el Future
, porque de lo contrario obtendrá una NullPointerException
.
Parece un mal diseño para el Runnable saber algo sobre el ejecutor en el que se está ejecutando, o lanzar un error si alcanzar 10 no es un estado de error es un hack.
¿Puedes hacer el bucle a 10 fuera de la programación y ejecución? Esto puede requerir el uso de un ejecutor no programador, ya que usted mismo los programaría manualmente.