Como definir um timer em Java?

151

Como definir um timer, por 2 minutos, para tentar se conectar a um banco de dados e lançar uma exceção se houver algum problema na conexão?

Ankita
fonte
1
Coul o OP esclarecer se eles desejam simples tentar a ação por pelo menos 2 minutos, ou se a exceção deve ser lançada agora mais tarde nos dois minutos, mesmo se uma tentativa de conexão estiver em andamento
thecoshman

Respostas:

280

Portanto, a primeira parte da resposta é como fazer o que o sujeito pergunta, pois foi assim que eu o interpretei inicialmente e algumas pessoas pareciam achar úteis. A questão foi esclarecida e estendi a resposta para resolver isso.

Definir um temporizador

Primeiro você precisa criar um timer (estou usando a java.utilversão aqui):

import java.util.Timer;

..

Timer timer = new Timer();

Para executar a tarefa uma vez que você faria:

timer.schedule(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);

Para repetir a tarefa após a duração, você faria:

timer.scheduleAtFixedRate(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000, 2*60*1000);

// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);

Fazendo um tempo limite da tarefa

Para fazer especificamente o que a pergunta esclarecida pede, que está tentando executar uma tarefa por um determinado período de tempo, você pode fazer o seguinte:

ExecutorService service = Executors.newSingleThreadExecutor();

try {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            // Database task
        }
    };

    Future<?> f = service.submit(r);

    f.get(2, TimeUnit.MINUTES);     // attempt the task for two minutes
}
catch (final InterruptedException e) {
    // The thread was interrupted during sleep, wait or join
}
catch (final TimeoutException e) {
    // Took too long!
}
catch (final ExecutionException e) {
    // An exception from within the Runnable task
}
finally {
    service.shutdown();
}

Isso será executado normalmente com exceções se a tarefa for concluída em 2 minutos. Se executar mais que isso, a TimeoutException será lançada.

Um problema é que, embora você receba uma TimeoutException após os dois minutos, a tarefa continuará sendo executada , embora presumivelmente um banco de dados ou uma conexão de rede acabe atingindo o tempo limite e lançando uma exceção no encadeamento. Mas esteja ciente de que pode consumir recursos até que isso aconteça.

andrewmu
fonte
Oh, eu acho que você tem o meu problema errado, eu tenho que tentar várias vezes para se conectar ao banco de dados de até 2 minutos toda vez que
Ankita
Lamento, mas a minha exigência é que eu quero dar 2 minutos para se conectar ao banco de dados e, em seguida, ele irá apenas jogar algum erro message.It é como eu quero definir um limite de tempo para tentar se conectar ao banco de dados
Ankita
7
LEITORES ATENÇÃO: Esta resposta é flagrantemente errada. Ele define um cronômetro para aguardar 2 minutos e, em seguida, executa uma consulta ao banco de dados após esse atraso de 2 minutos e, em seguida, executa-o novamente a cada 2 minutos. O que NÃO faz é executar a consulta do banco de dados imediatamente e falhar após 2 minutos, que é o que acho que a pergunta foi solicitada (conforme esclarecido no comentário).
AgilePro 14/02
2
@AgilePro Isso era verdade. Não respondi à pergunta, como ela acabou sendo declarada, e agora a atualizei para resolver isso.
22613 Andrewmu
1
@ErnestasGruodis As principais APIs listam o construtor como público: docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer () Você pode ter uma classe Timer diferente em seu caminho de classe - tente java. util.Timer como a classe
andrewmu
25

Usa isto

long startTime = System.currentTimeMillis();
long elapsedTime = 0L.

while (elapsedTime < 2*60*1000) {
    //perform db poll/check
    elapsedTime = (new Date()).getTime() - startTime;
}

//Throw your exception
nimWM
fonte
1
hmm ... esse trabalho seria tecnicamente, exceto que ele não cobre casos de ponta, onde o tempo se esgote como você está realizando uma pesquisa DB, o que pode ser exigido pelo OP
thecoshman
1
Esta é a única resposta correta. Ele será executado em um único encadeamento e calculará o horário final sem desvio. Usar um TimerTask é exatamente a coisa errada a se fazer neste caso. Estou surpreso com quantos exemplos no StackOverflow sugerem esse mesmo tipo de coisa errada.
AgilePro 14/01
1
@ thoshoshman - as implementações do timer NÃO interrompem a operação do banco de dados depois que ela está em andamento, nem isso. De qualquer forma, você pode controlar apenas o horário em que inicia a operação do banco de dados. Há um equívoco comum de que você precisa de um "temporizador" para cronometrar as coisas, mas não precisa. Você só precisa fazer alguma coisa e, usando o horário atual, certifique-se de não fazê-lo por muito tempo.
AgilePro 14/01
digamos que você precise retornar a conexão ou lançar após EXATAMENTE dois minutos, isso não funcionará. isso acontecerá se APÓS dois minutos de tentativa de conexão, você ainda não conseguiu se conectar. Em uma situação em que a verificação da conexão leva, digamos, duas semanas, isso levará muito tempo para gerar uma exceção.
thecoshman
14
Na verdade, esse é um estilo de codificação muito ruim, já que o loop while é executado constantemente e verifica coisas ... ruins para a CPU e ruins para o tempo de vida da bateria.
Infinito
11

Ok, acho que entendi o seu problema agora. Você pode usar um futuro para tentar fazer alguma coisa e, em seguida, expirar um pouco se nada aconteceu.

Por exemplo:

FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
  @Override
  public Void call() throws Exception {
    // Do DB stuff
    return null;
  }
});

Executor executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(task);

try {
  task.get(5, TimeUnit.SECONDS);
}
catch(Exception ex) {
  // Handle your exception
}
andrewmu
fonte
Exceção é lançada, mas o programa não está sendo finalizado.
Ankita
2
Você pode usar a classe ExecutorService em vez de Executor. Possui o método shutdown () para parar o executor.
Ritos
1
Os executores engolirão exceções lançadas que você não lida especificamente com seu Callable / Runnable. Se o seu Runnable / Callable não capturar e manipular a exceção em si e for fornecida a você em relação à sua, você deverá subclassificar o ScheduledExecutorService e substituir afterExecute (certifique-se de chamar super.afterExecute ()). O segundo argumento para AfterExecute será o throwable do Runnable / mobilizável
adam
3
    new java.util.Timer().schedule(new TimerTask(){
        @Override
        public void run() {
            System.out.println("Executed...");
           //your code here 
           //1000*5=5000 mlsec. i.e. 5 seconds. u can change accordngly 
        }
    },1000*5,1000*5); 
Mahadev Mane
fonte
basta copiar a praga acima do código que funcionará bem. Eu dei duas vezes o 'tempo' pela primeira vez pela primeira vez para executar esse código e o segundo é pelo intervalo de tempo.
Mahadev Mane
A documentação do Timer recomenda o uso da estrutura Executor. docs.oracle.com/javase/10/docs/api/java/util/Timer.html
Karan Khanna
1

[Android] se alguém quer implementar o timer no android usando java .

você precisa usar o thread da interface do usuário como este para executar operações.

Timer timer = new Timer();
timer.schedule(new TimerTask() {
           @Override
            public void run() {
                ActivityName.this.runOnUiThread(new Runnable(){
                    @Override
                      public void run() {
                       // do something
                      }        
                });
            }
        }, 2000));
Abhishek Garg
fonte