Pergunta
Eu gostaria de ter um java.utils.Timer com um tempo reconfigurável em java. Preciso definir um evento único para ocorrer em X segundos.Se nada acontecer entre o momento em que o cronômetro foi criado e X segundos, o evento ocorrerá normalmente.
Se, no entanto, antes de decorridos X segundos, eu decidir que o evento deve ocorrer após Y segundos, então quero poder dizer ao cronômetro para redefinir seu tempo para que o evento ocorra em Y segundos.Por exemplo.o cronômetro deve ser capaz de fazer algo como:
Timer timer = new Timer();
timer.schedule(timerTask, 5000); //Timer starts in 5000 ms (X)
//At some point between 0 and 5000 ms...
setNewTime(timer, 8000); //timerTask will fire in 8000ms from NOW (Y).
Não vejo uma maneira de fazer isso usando o cronômetro de utilitários, pois se você chamar cancel() não poderá agendá-lo novamente.
A única maneira de replicar esse comportamento é usando javax.swing.Timer e envolve parar o cronômetro original e criar um novo.ou seja:
timer.stop();
timer = new Timer(8000, ActionListener);
timer.start();
Existe uma maneira mais fácil??
Solução
De acordo com Timer
documentação, em Java 1.5 em diante, você deve preferir o ScheduledThreadPoolExecutor
em vez de.(Você pode querer criar este executor usando Executors
.newSingleThreadScheduledExecutor()
para facilidade de uso;cria algo muito parecido com um Timer
.)
O legal é que quando você agenda uma tarefa (ligando schedule()
), ele retorna um ScheduledFuture
objeto.Você pode usar isso para cancelar a tarefa agendada.Você estará então livre para enviar uma nova tarefa com um horário de acionamento diferente.
Hora prevista de chegada:O Timer
documentação vinculada a não diz nada sobre ScheduledThreadPoolExecutor
, No entanto, o OpenJDK versão tinha isto a dizer:
Java 5.0 introduziu o
java.util.concurrent
pacote e um dos utilitários de concorrência nele é oScheduledThreadPoolExecutor
que é um pool de threads para executar repetidamente tarefas a uma determinada taxa ou atraso.É efetivamente um substituto mais versátil para oTimer
/TimerTask
combinação, pois permite vários tópicos de serviço, aceita várias unidades de tempo e não requer subclassificaçãoTimerTask
(apenas implementeRunnable
).ConfigurandoScheduledThreadPoolExecutor
com um thread torna equivalente aTimer
.
Outras dicas
Se seu Timer
só terá uma tarefa para executar, então sugiro subclassificá-la:
import java.util.Timer;
import java.util.TimerTask;
public class ReschedulableTimer extends Timer
{
private Runnable task;
private TimerTask timerTask;
public void schedule(Runnable runnable, long delay)
{
task = runnable;
timerTask = new TimerTask()
{
@Override
public void run()
{
task.run();
}
};
this.schedule(timerTask, delay);
}
public void reschedule(long delay)
{
timerTask.cancel();
timerTask = new TimerTask()
{
@Override
public void run()
{
task.run();
}
};
this.schedule(timerTask, delay);
}
}
Você precisará trabalhar no código para adicionar verificações de uso indevido, mas deve conseguir o que deseja.O ScheduledThreadPoolExecutor
também não parece ter incorporado suporte para o reprogramamento de tarefas existentes, mas uma abordagem semelhante também deveria funcionar.
Todo o trecho de código é assim ....Espero que seja uma ajuda completa
{
Runnable r = new ScheduleTask();
ReschedulableTimer rescheduleTimer = new ReschedulableTimer();
rescheduleTimer.schedule(r, 10*1000);
public class ScheduleTask implements Runnable {
public void run() {
//Do schecule task
}
}
class ReschedulableTimer extends Timer {
private Runnable task;
private TimerTask timerTask;
public void schedule(Runnable runnable, long delay) {
task = runnable;
timerTask = new TimerTask() {
public void run() {
task.run();
}
};
timer.schedule(timerTask, delay);
}
public void reschedule(long delay) {
System.out.println("rescheduling after seconds "+delay);
timerTask.cancel();
timerTask = new TimerTask() {
public void run() {
task.run();
}
};
timer.schedule(timerTask, delay);
}
}
}
Você precisa agendar uma tarefa recorrente?Nesse caso, recomendo que você considere usar Quartzo.
Eu não acho que seja possível fazer isso com Timer/TimerTask
, mas dependendo do que exatamente você deseja alcançar, você pode ficar satisfeito em usar java.util.concurrent.ScheduledThreadPoolExecutor
.
é isso que estou experimentando.Tenho uma classe que pesquisa um banco de dados a cada 60 segundos usando um TimerTask.
na minha classe principal, mantenho a instância do Timer e uma instância da minha subclasse local do TimerTask.a classe principal possui um método para definir o intervalo de pesquisa (digamos, de 60 a 30).nele, cancelo meu TimerTask (que é minha subclasse, onde sobrescrevi o método cancel() para fazer alguma limpeza, mas isso não deveria importar) e depois o torno nulo.eu recrio uma nova instância dele e agendo a nova instância no novo intervalo no temporizador existente.
como o Timer em si não é cancelado, o thread que ele estava usando permanece ativo (e o mesmo aconteceria com qualquer outro TimerTasks dentro dele), e o antigo TimerTask é substituído por um novo, que é o mesmo, mas VIRGIN (já que o TimerTask antigo teria sido executado ou agendado, não é mais VIRGEM, conforme exigido para agendamento).
quando quero desligar o cronômetro inteiro, cancelo e anulo o TimerTask (o mesmo que fiz ao alterar o tempo, novamente, para limpar recursos em minha subclasse de TimerTask) e, em seguida, cancelo e anulo o próprio cronômetro.
Aqui está o exemplo para temporizador reinicializável.Tente alterá-lo para sua conveniência ...
package com.tps.ProjectTasks.TimeThread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* Simple demo that uses java.util.Timer to schedule a task to execute
* every 5 seconds and have a delay if you give any input in console.
*/
public class DateThreadSheduler extends Thread {
Timer timer;
BufferedReader br ;
String data = null;
Date dNow ;
SimpleDateFormat ft;
public DateThreadSheduler() {
timer = new Timer();
timer.schedule(new RemindTask(), 0, 5*1000);
br = new BufferedReader(new InputStreamReader(System.in));
start();
}
public void run(){
while(true){
try {
data =br.readLine();
if(data != null && !data.trim().equals("") ){
timer.cancel();
timer = new Timer();
dNow = new Date( );
ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Modified Current Date ------> " + ft.format(dNow));
timer.schedule(new RemindTask(), 5*1000 , 5*1000);
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
System.out.format("Printint the time and date was started...\n");
new DateThreadSheduler();
}
}
class RemindTask extends TimerTask {
Date dNow ;
SimpleDateFormat ft;
public void run() {
dNow = new Date();
ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Current Date: " + ft.format(dNow));
}
}
Este exemplo imprime a data e hora atuais a cada 5 segundos... Mas se você fornecer qualquer entrada no console, o cronômetro será atrasado para executar a tarefa de entrada fornecida...
Criei uma classe de cronômetro própria para um propósito semelhante;Sinta-se livre para usá-lo:
public class ReschedulableTimer extends Timer {
private Runnable mTask;
private TimerTask mTimerTask;
public ReschedulableTimer(Runnable runnable) {
this.mTask = runnable;
}
public void schedule(long delay) {
if (mTimerTask != null)
mTimerTask.cancel();
mTimerTask = new TimerTask() {
@Override
public void run() {
mTask.run();
}
};
this.schedule(mTimerTask, delay);
}
}