0Pricing
Java Academy · Lección

ScheduledExecutorService para tareas recurrentes

Programe tareas con frecuencias o retrasos fijos para realizar sondeos y tareas de mantenimiento en segundo plano.

ScheduledExecutorService para tareas recurrentes es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.

¿Por qué usar ScheduledExecutorService?

ScheduledExecutorService amplía ExecutorService para admitir la programación de tareas. Sustituye las clases heredadas Timer/TimerTask por un programador respaldado por un grupo de hilos y seguro frente a excepciones.

import java.util.concurrent.*;

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

// One-shot delay
scheduler.schedule(
    () -> System.out.println("Runs once after 3 seconds"),
    3, TimeUnit.SECONDS
);

// Don't forget to shut down eventually:
// scheduler.shutdown();

schedule: retraso de una sola ejecución

schedule(task, delay, unit) ejecuta la tarea una vez después del retraso especificado. Funciona tanto con Runnable como con Callable:

ScheduledExecutorService s = Executors.newScheduledThreadPool(1);

// Runnable:
ScheduledFuture<?> sf1 = s.schedule(
    () -> System.out.println("Runnable fired!"), 2, TimeUnit.SECONDS);

// Callable:
ScheduledFuture<Integer> sf2 = s.schedule(
    () -> { System.out.println("Callable fired!"); return 42; },
    2, TimeUnit.SECONDS);

System.out.println(sf2.get()); // 42 (after 2 seconds)

scheduleAtFixedRate

scheduleAtFixedRate(task, initialDelay, period, unit) ejecuta la tarea repetidamente a una frecuencia fija. Si una tarea tarda más que el periodo, la siguiente ejecución comienza inmediatamente después de que termine la anterior, sin solaparse.

ScheduledExecutorService s = Executors.newScheduledThreadPool(1);
AtomicInteger count = new AtomicInteger();

ScheduledFuture<?> sf = s.scheduleAtFixedRate(
    () -> System.out.println("Tick " + count.incrementAndGet()),
    0,   // initial delay
    1,   // period
    TimeUnit.SECONDS
);

Thread.sleep(5000);
sf.cancel(false); // stop after 5 ticks
s.shutdown();

scheduleWithFixedDelay

scheduleWithFixedDelay(task, initialDelay, delay, unit) espera el retraso especificado DESPUÉS de que termine cada tarea antes de iniciar la siguiente. Es adecuado para sondeos en los que la duración de la tarea varía.

s.scheduleWithFixedDelay(
    () -> {
        System.out.println("Polling... " + Instant.now());
        // variable-length polling task
    },
    0,  // no initial delay
    5,  // 5-second gap AFTER each completion
    TimeUnit.SECONDS
);
// Next execution = task end + 5 seconds (not task start)

Frecuencia fija frente a retraso fijo

Diferencia principal:

  • scheduleAtFixedRate: siguiente inicio = último inicio + periodo (temporización sin desviación)
  • scheduleWithFixedDelay: siguiente inicio = última finalización + retraso (intervalo garantizado entre ejecuciones)

Use fixedRate para señales de latido y fixedDelay para sondeos en los que la duración de la tarea varía.

ScheduledFuture: cancelación

schedule/scheduleAtFixedRate/scheduleWithFixedDelay devuelven un ScheduledFuture. Llame a cancel(false) para detener las ejecuciones futuras sin interrumpir la que está en curso:

ScheduledFuture<?> sf = scheduler.scheduleAtFixedRate(
    () -> System.out.println("Heartbeat"), 0, 1, TimeUnit.SECONDS);

// Cancel after 5 seconds
scheduler.schedule(() -> sf.cancel(false), 5, TimeUnit.SECONDS);

Gestión de excepciones en tareas programadas

Si una tarea programada lanza una excepción no capturada, el programador detiene silenciosamente las ejecuciones recurrentes: no se producen más ejecuciones. Envuélvala siempre en un bloque try-catch:

scheduler.scheduleAtFixedRate(() -> {
    try {
        // risky work
        if (Math.random() < 0.3) throw new RuntimeException("transient");
        System.out.println("Success");
    } catch (Exception e) {
        System.err.println("Task error: " + e.getMessage());
        // task continues to run on next interval
    }
}, 0, 2, TimeUnit.SECONDS);

Práctica: actualización de la caché

Use una tarea programada para actualizar una caché periódicamente:

class PriceCache {
    private volatile Map<String, Double> prices = new HashMap<>();
    
    PriceCache(ScheduledExecutorService scheduler) {
        scheduler.scheduleAtFixedRate(this::refresh, 0, 30, TimeUnit.SECONDS);
    }
    
    private void refresh() {
        System.out.println("Refreshing prices...");
        // prices = fetchFromDatabase();
    }
    
    Double getPrice(String symbol) { return prices.get(symbol); }
}

Práctica: reintentos con backoff

Implemente reintentos con retroceso exponencial mediante tareas programadas:

void retryWithBackoff(Runnable task, int maxRetries, ScheduledExecutorService s) {
    AtomicInteger attempts = new AtomicInteger(0);
    long[] delay = {1}; // seconds
    
    Runnable wrapper = new Runnable() {
        public void run() {
            try {
                task.run();
            } catch (Exception e) {
                int n = attempts.incrementAndGet();
                if (n < maxRetries) {
                    delay[0] *= 2;
                    s.schedule(this, delay[0], TimeUnit.SECONDS);
                } else System.err.println("Max retries reached");
            }
        }
    };
    s.execute(wrapper);
}

Supervisión: getDelay y getQueue

Inspeccione el estado del planificador:

ScheduledFuture<?> sf = scheduler.schedule(() -> {}, 10, TimeUnit.SECONDS);
System.out.println("Delay remaining: " + sf.getDelay(TimeUnit.SECONDS) + "s");

// ThreadPoolExecutor provides queue inspection:
if (scheduler instanceof ScheduledThreadPoolExecutor ste) {
    System.out.println("Queue size: " + ste.getQueue().size());
}

Apagado y vaciado

Al apagar el sistema, decida si las tareas programadas deben seguir ejecutándose:

ScheduledThreadPoolExecutor ste = (ScheduledThreadPoolExecutor)
    Executors.newScheduledThreadPool(2);

// Cancel scheduled tasks on shutdown (default: false = they run)
ste.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
ste.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);

ste.shutdown();

Comprobación rápida

Una tarea programada con scheduleAtFixedRate(..., 1, TimeUnit.SECONDS) tarda 3 segundos en completarse. ¿Cómo gestiona esto el planificador?

Resumen: ScheduledExecutorService

Conceptos clave:

  • schedule() — ejecución única con retraso
  • scheduleAtFixedRate() — temporización sin deriva (de inicio a inicio)
  • scheduleWithFixedDelay() — intervalo garantizado (del final al inicio)
  • Las excepciones no capturadas detienen silenciosamente las tareas recurrentes — envuélvalas siempre en un bloque try-catch
  • Cancele con ScheduledFuture.cancel(false)

Preguntas frecuentes

¿La lección «ScheduledExecutorService para tareas recurrentes» es gratis?

Sí — el texto completo de «ScheduledExecutorService para tareas recurrentes» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.

¿Qué aprenderé en «ScheduledExecutorService para tareas recurrentes»?

Programe tareas con frecuencias o retrasos fijos para realizar sondeos y tareas de mantenimiento en segundo plano. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Java Academy?

No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «ScheduledExecutorService para tareas recurrentes»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Java Academy?

Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. ExecutorService y tipos de grupos de hilos
  2. Envío de tareas: Runnable frente a Callable
  3. Future y gestión de errores
  4. ScheduledExecutorService para tareas recurrentes
← Volver a Java Academy