Temporizador Java

Temporizador Java

1. Timer - o básico

TimereTimerTask são classes utilitárias java usadas para agendar tarefas em um thread em segundo plano. Em poucas palavras -TimerTask is the task to perform and Timer is the scheduler.

2. Agende uma tarefa uma vez

Vamos começar simplesmenterunning a single task com a ajuda deTimer:

@Test
public void givenUsingTimer_whenSchedulingTaskOnce_thenCorrect() {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on: " + new Date() + "n" +
              "Thread's name: " + Thread.currentThread().getName());
        }
    };
    Timer timer = new Timer("Timer");

    long delay = 1000L;
    timer.schedule(task, delay);
}

Observe que se estivermos executando este é um teste JUnit, devemos adicionar uma chamadaThread.sleep(delay * 2) para permitir que o encadeamento do Timer execute a tarefa antes que o teste Junit pare de ser executado.

3. Agende uma tarefa repetida em um intervalo

Em seguida - vamosschedule a task to run at a pre-defined interval.

Faremos uso da APIscheduleAtFixedRate(repeatedTask, delay, period) - que agenda a tarefa para execução repetida de taxa fixa, começando após o atraso especificado. As execuções subsequentes ocorrem em intervalos regulares, separadas pelo período especificado:

@Test
public void givenUsingTimer_whenSchedulingRepeatedTask_thenCorrect(){
    TimerTask repeatedTask = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    Timer timer = new Timer("Timer");

    long delay  = 1000L;
    long period = 1000L;
    timer.scheduleAtFixedRate(repeatedTask, delay, period);
}

Observe que - se uma execução for atrasada por qualquer motivo (como coleta de lixo ou outra atividade em segundo plano), duas ou mais execuções ocorrerão em rápida sucessão para "recuperar o atraso".

3.1. Agende uma tarefa diária

A seguir - vamosrun a task once a day:

@Test
public void givenUsingTimer_whenSchedulingDailyTask_thenCorrect() {
    TimerTask repeatedTask = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    Timer timer = new Timer("Timer");

    long delay = 1000L;
    long period = 1000L * 60L * 60L * 24L;
    timer.scheduleAtFixedRate(repeatedTask, delay, period);
}

4. CancelarTimer eTimerTask

A execução de uma tarefa pode ser cancelada de algumas maneiras:

4.1. Cancele oTimerTask dentro deRun

Chamando o métodoTimerTask.cancel() dentro da implementação do métodorun() do próprioTimerTask:

@Test
public void givenUsingTimer_whenCancelingTimerTask_thenCorrect()
  throws InterruptedException {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
            cancel();
        }
    };
    Timer timer = new Timer("Timer");

    timer.scheduleAtFixedRate(task, 1000L, 1000L);

    Thread.sleep(1000L * 2);
}

4.2. Cancelar oTimer

Chamando o métodoTimer.cancel() em um objetoTimer:

@Test
public void givenUsingTimer_whenCancelingTimer_thenCorrect()
  throws InterruptedException {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    Timer timer = new Timer("Timer");

    timer.scheduleAtFixedRate(task, 1000L, 1000L);

    Thread.sleep(1000L * 2);
    timer.cancel();
}

4.3. Pare a linha deTimerTask dentro deRun

Você também pode interromper o encadeamento dentro do métodorun da tarefa, cancelando assim a tarefa inteira:

@Test
public void givenUsingTimer_whenStoppingThread_thenTimerTaskIsCancelled()
  throws InterruptedException {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
            // TODO: stop the thread here
        }
    };
    Timer timer = new Timer("Timer");

    timer.scheduleAtFixedRate(task, 1000L, 1000L);

    Thread.sleep(1000L * 2);
}

Observe a instrução TODO na implementação derun - para executar este exemplo simples, precisaremos realmente parar o thread.

Em uma implementação de thread customizada do mundo real, a interrupção do thread deve ser suportada, mas neste caso podemos ignorar a reprovação e usar a APIstop simples na própria classe Thread.

5. Timer VSExecutorService

Você também pode fazer bom uso de um ExecutorService para agendar tarefas do cronômetro, em vez de usá-lo.

Aqui está um exemplo rápido de como executar uma tarefa repetida em um intervalo especificado:

@Test
public void givenUsingExecutorService_whenSchedulingRepeatedTask_thenCorrect()
  throws InterruptedException {
    TimerTask repeatedTask = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    long delay  = 1000L;
    long period = 1000L;
    executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS);
    Thread.sleep(delay + period * 3);
    executor.shutdown();
}

Então, quais são as principais diferenças entre a soluçãoTimereExecutorService:

  • Timer pode ser sensível a mudanças no relógio do sistema; ScheduledThreadPoolExecutor não é

  • Timer tem apenas um thread de execução; ScheduledThreadPoolExecutor pode ser configurado com qualquer número de threads

  • As exceções de tempo de execução lançadas dentro deTimerTask eliminam o encadeamento, portanto, as tarefas agendadas seguintes não funcionarão mais; comScheduledThreadExecutor - a tarefa atual será cancelada, mas o resto continuará a ser executado

6. Conclusão

Este tutorial ilustrou as várias maneiras de usar a infraestrutura simples, porém flexível,TimereTimerTask integrada em Java para agendar tarefas rapidamente. É claro que existem soluções muito mais complexas e completas no mundo Java se você precisar delas - comothe Quartz library - mas este é um bom lugar para começar.

A implementação desses exemplos pode ser encontrada emthe github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.