java: executa uma função após um número específico de segundos

148

Eu tenho uma função específica que quero ser executada após 5 segundos. Como posso fazer isso em Java?

Encontrei javax.swing.timer, mas não consigo entender como usá-lo. Parece que estou procurando algo muito mais simples do que esta classe fornece.

Por favor, adicione um exemplo simples de uso.

ufk
fonte
Deseja esperar 5 segundos e depois executar alguma coisa ou deseja continuar fazendo outra coisa nos 5 segundos?
13132
Eu quero continuar fazendo outra coisa
ufk

Respostas:

229
new java.util.Timer().schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
            }
        }, 
        5000 
);

EDITAR:

javadoc diz:

Depois que a última referência ao vivo para um objeto Timer desaparece e todas as tarefas pendentes concluem a execução, o encadeamento de execução de tarefas do timer termina normalmente (e fica sujeito à coleta de lixo). No entanto, isso pode demorar arbitrariamente para ocorrer.

tangens
fonte
1
Se você executar esse código, vazará threads. Certifique-se de limpar o cronômetro quando terminar.
22410 skaffman
1
@skaffman: adicionei uma declaração do javadoc. Você realmente tem que limpar depois de ligar para a programação?
tangens 13/02/10
1
Pode estar tudo bem, mas pode não estar. Se você executar esse fragmento de código várias vezes, haverá threads soltos, sem meios de ordená-los.
22410 skaffman
5
import java.util.Timer; import java.util.TimerTask;pode tornar mais óbvio que isso não é verdade javax.swing.Timer. / Observe que, se você estiver usando o Swing (e realmente o AWT), não deve fazer nada para alterar os componentes nos segmentos que não são do segmento de distribuição de eventos (EDT) ( java.util.Timertarefas ruins; javax.swing.Timerações boas).
Tom Hawtin - defina
2
@PaulAlexander De acordo com os documentos, chamar o cancelmétodo do timer no final do método de execução limparia o encadeamento de execução das TimerTasks.
Dandalf
58

Algo assim:

// When your program starts up
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

// then, when you want to schedule a task
Runnable task = ....    
executor.schedule(task, 5, TimeUnit.SECONDS);

// and finally, when your program wants to exit
executor.shutdown();

Existem vários outros métodos de fábrica nos Executorquais você pode usar, se desejar mais threads no pool.

E lembre-se, é importante desligar o executor quando terminar. O shutdown()método desligará o pool de threads quando a última tarefa for concluída e bloqueará até que isso aconteça. shutdownNow()encerrará o conjunto de encadeamentos imediatamente.

skaffman
fonte
24

Exemplo de uso javax.swing.Timer

Timer timer = new Timer(3000, new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent arg0) {
    // Code to be executed
  }
});
timer.setRepeats(false); // Only execute once
timer.start(); // Go go go!

Este código será executado apenas uma vez e a execução ocorre em 3000 ms (3 segundos).

Como o camickr menciona, você deve procurar " Como usar temporizadores giratórios " para uma breve introdução.

zpon
fonte
6

Meu código é o seguinte:

new java.util.Timer().schedule(

    new java.util.TimerTask() {
        @Override
        public void run() {
            // your code here, and if you have to refresh UI put this code: 
           runOnUiThread(new   Runnable() {
                  public void run() {
                            //your code

                        }
                   });
        }
    }, 
    5000 
);
user2885850
fonte
5

Como uma variação da resposta do @tangens: se você não puder esperar o coletor de lixo limpar seu encadeamento, cancele o cronômetro no final do seu método de execução.

Timer t = new java.util.Timer();
t.schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
                // close the thread
                t.cancel();
            }
        }, 
        5000 
);
Dandalf
fonte
Não deve Timer tser declarado, finalpois está sendo acessado dentro de uma classe interna?
Joshua Pinter
1
@JoshuaPinter Sim, ele deve ser declarado final, mas não precisa ser explicitamente declarado final em pelo menos Java 8. Ele só precisa ser "efetivamente final" ( javarevisited.blogspot.com/2015/03/03 )
Dandalf
4

Sua pergunta original menciona o "Temporizador de oscilação". Se, de fato, sua pergunta está relacionada ao SWing, você deve usar o Swing Timer e NÃO o util.Timer.

Leia a seção do tutorial do Swing em " Como usar temporizadores " para obter mais informações.

camickr
fonte
4

você poderia usar a função Thread.Sleep ()

Thread.sleep(4000);
myfunction();

Sua função será executada após 4 segundos. No entanto, isso pode pausar o programa inteiro ...

dale
fonte
E apenas garante que a execução será executada após 4s, o que também pode significar após 10s!
questzen
2
Questzen, você verá que todos os métodos aqui fazem isso. De fato, mesmo que você esteja agendando algo no nível do sistema operacional, geralmente você só pode garantir um tempo mínimo decorrido antes de um evento.
Ethan
Este não é o que pergunta real era
Inder Singh R
Eu apenas tive que dar um voto negativo - não uma resposta à pergunta em questão.
theMayer
OP disse em um comentário "eu quero continuar fazendo outra coisa"; esse código obviamente não.
Abhijit Sarkar
3

ScheduledThreadPoolExecutor tem essa capacidade, mas é bastante pesada.

Timer também possui essa capacidade, mas abre vários threads, mesmo se usado apenas uma vez.

Aqui está uma implementação simples com um teste (assinatura próxima ao Handler.postDelayed () do Android ):

public class JavaUtil {
    public static void postDelayed(final Runnable runnable, final long delayMillis) {
        final long requested = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                // The while is just to ignore interruption.
                while (true) {
                    try {
                        long leftToSleep = requested + delayMillis - System.currentTimeMillis();
                        if (leftToSleep > 0) {
                            Thread.sleep(leftToSleep);
                        }
                        break;
                    } catch (InterruptedException ignored) {
                    }
                }
                runnable.run();
            }
        }).start();
    }
}

Teste:

@Test
public void testRunsOnlyOnce() throws InterruptedException {
    long delay = 100;
    int num = 0;
    final AtomicInteger numAtomic = new AtomicInteger(num);
    JavaUtil.postDelayed(new Runnable() {
        @Override
        public void run() {
            numAtomic.incrementAndGet();
        }
    }, delay);
    Assert.assertEquals(num, numAtomic.get());
    Thread.sleep(delay + 10);
    Assert.assertEquals(num + 1, numAtomic.get());
    Thread.sleep(delay * 2);
    Assert.assertEquals(num + 1, numAtomic.get());
}
AlikElzin-kilaka
fonte
dá sono aviso chamado em um loop
shareef
O whileé apenas para ignorar a interrupção.
AlikElzin-kilaka
2

Todos os outros desatadores precisam executar seu código dentro de um novo thread. Em alguns casos de uso simples, você pode esperar um pouco e continuar a execução no mesmo encadeamento / fluxo.

O código abaixo demonstra essa técnica. Lembre-se de que isso é semelhante ao que o java.util.Timer faz sob o capô, mas é mais leve.

import java.util.concurrent.TimeUnit;
public class DelaySample {
    public static void main(String[] args) {
       DelayUtil d = new DelayUtil();
       System.out.println("started:"+ new Date());
       d.delay(500);
       System.out.println("half second after:"+ new Date());
       d.delay(1, TimeUnit.MINUTES); 
       System.out.println("1 minute after:"+ new Date());
    }
}

Implementação DelayUtil

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class DelayUtil {
    /** 
    *  Delays the current thread execution. 
    *  The thread loses ownership of any monitors. 
    *  Quits immediately if the thread is interrupted
    *  
    * @param duration the time duration in milliseconds
    */
   public void delay(final long durationInMillis) {
      delay(durationInMillis, TimeUnit.MILLISECONDS);
   }

   /** 
    * @param duration the time duration in the given {@code sourceUnit}
    * @param unit
    */
    public void delay(final long duration, final TimeUnit unit) {
        long currentTime = System.currentTimeMillis();
        long deadline = currentTime+unit.toMillis(duration);
        ReentrantLock lock = new ReentrantLock();
        Condition waitCondition = lock.newCondition();

        while ((deadline-currentTime)>0) {
            try {
                lock.lockInterruptibly();    
                waitCondition.await(deadline-currentTime, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            } finally {
                lock.unlock();
            }
            currentTime = System.currentTimeMillis();
        }
    }
}
Valchkou
fonte
2
public static Timer t;

public synchronized void startPollingTimer() {
        if (t == null) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                   //Do your work
                }
            };

            t = new Timer();
            t.scheduleAtFixedRate(task, 0, 1000);
        }
    }
Amol K
fonte
2
Embora esse código possa responder à pergunta, fornecer um contexto adicional a respeito de por que e / ou como esse código responde à pergunta melhora seu valor a longo prazo.
Mateus