Java Scheduling

  1. Agende um processo usando os métodos de interface ScheduledExecutorService em Java
  2. Agende um thread usando a classe Timer em Java

O agendamento é o processo de execução de uma tarefa ou função em um intervalo fixo de tempo. A programação encontra seu uso na execução de processos em lote, enviando gatilhos baseados em eventos, como desejos de aniversário, enviando notificações push. Esses processos devem ser executados em um horário bem definido com base nas condições e no intervalo de tempo fornecidos.

Agende um processo usando os métodos de interface ScheduledExecutorService em Java

package scheduling;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ScheduleTask {
    private static int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        Runnable executeTask = () -> {
            counter++;
            System.out.println("Task" + counter);
        };

        ScheduledFuture<?> scheduleAtFixedRate = service.scheduleAtFixedRate(executeTask, 5, 1, TimeUnit.SECONDS);

        while (true) {
            Thread.sleep(1000);
            if (counter == 5) {
                System.out.println("Stopping the scheduled task!");
                scheduleAtFixedRate.cancel(true);
                service.shutdown();
                break;
            }
        }
    }
}

No código acima, primeiro, uma variável de contador estática é inicializada com valor zero. O newScheduledThreadPool é um método estático da classe Executors. O método cria um pool de threads que deve ser executado periodicamente com o parâmetro fornecido na lista de argumentos. Portanto, em nosso caso, um único encadeamento é criado para execução, pois o parâmetro na lista de argumentos de métodos define o número de conjuntos de encadeamentos. O método retorna uma instância de ScheduledExecutorService que é armazenada na variável de referência serviço e lança IllegalArgumentException se o tamanho do pool for menor que zero.

O Runnable é uma interface que qualquer classe pode estender e é a interface funcional. Ele possui apenas um método estático como o método run e destina-se à execução do thread. Usando a expressão lambda expressa como o símbolo ()-> parênteses e uma seta, a estrutura afirma que não estamos passando nenhum argumento para o método run. Definimos as instruções na definição do método de execução. A instrução presente dentro do bloco irá incrementar a variável do contador e imprimir a tarefa na saída do console. Todas essas instruções são referenciadas pela variável chamada de variável executeTask.

A variável de referência service chama o método scheduleAtFixedRate da interface ScheduledExecutorService. O método cria e executa a tarefa periódica que deve ser executada após o atraso inicial e posteriormente dentro do período determinado. Leva quatro parâmetros, um comando runnable que deve ser executado e a variável initialDelay é o tempo para atrasar a primeira execução, period denota a duração entre execuções sucessivas e unit é a unidade de tempo em segundos , minutos e horas. A thread começa a ser executada assim que o método é chamado.

No loop while, primeiro, o thread em execução atual é forçado a hibernar. O método Thread.sleep() interrompe temporariamente a thread atualmente em execução pelo tempo definido. O parâmetro é o número em milissegundos para o qual o segmento de trabalho atual deve ser interrompido. O método lança IllegalArgumentException se o valor for negativo e InterruptedException se o thread atual for interrompido. Posteriormente, o valor de um contador é verificado com um valor definido. Essa verificação é aplicada para executar o método while por um determinado número de vezes. Caso contrário, o bloco operará por um número infinito que nunca terminará. No bloco while, a variável scheduleAtFixedRate chama o método cancel, que cancela a execução atual da thread. A função também recebe um parâmetro booleano que indica se o thread em execução atual pode interromper ou não.

O método service.shutdown inicia o processo de desligamento no qual as tarefas enviadas anteriormente devem ser executadas e nada de novo é aceito.

A saída do bloco de código acima é a seguinte.

Task1
Task2
Task3
Task4
Task5
Stopping the scheduled task!

Agende um thread usando a classe Timer em Java

Abaixo está o bloco de código simples que instancia dois objetos de classe definidos pelo usuário usando seus construtores. TimerImplementation é a classe definida pelo usuário para o mesmo. Uma instância de Timer é criada para criar um novo encadeamento. O objeto recém-criado de um cronômetro irá então chamar o método scheduleAtFixedRate. Este método usa parâmetros como task que precisa ser agendada, delay atrasa a tarefa em milissegundos e period é o tempo em milissegundos para execução sucessiva.

package timer;

import java.util.Timer;

public class UsingTimerClass {
    public static void main(String[] args) {
        TimerImplementation timer1 = new TimerImplementation("Thread1");
        TimerImplementation timer2 = new TimerImplementation("Thread2");

        Timer t = new Timer();
        t.scheduleAtFixedRate(timer1, 0, 2000);
        t.scheduleAtFixedRate(timer2, 0, 1000);
    }
}

Abaixo está a implementação da classe definida pelo usuário. A classe TimerImplementation estende a classe abstrata TimerTask que contém um único método abstrato denominado run. Nós estendemos a classe TimerTask em uma classe definida pelo usuário, então o método run é sobrescrito.

A classe tem um construtor definido pelo usuário que configura o nome definido pelo usuário para o objeto thread.

Podemos fornecer lógica real no método thread run. Inclui uma instrução como print que imprimirá o nome da thread atualmente em execução. Thread.currentThread().getName() retorna o nome do thread em execução atual. O método sleep é chamado em Thread1 que interrompe a execução por 1000 milissegundos. O método sleep lança InterruptedException se qualquer thread interromper o thread atual, e é por isso que ele é incluído no bloco try-catch.

package timer;

import java.util.TimerTask;

public class TimerImplementation extends TimerTask {

    private String name;

    public TimerImplementation(String n) {
        this.name = n;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " " + name);
        if ("Thread1".equalsIgnoreCase(name)) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Abaixo está a saída interminável do código acima. Como não definimos nenhuma condição de término no método run, o encadeamento será executado indefinidamente até que uma parada externa seja aplicada para encerrar a execução do encadeamento principal.

Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2