java: esegue una funzione dopo un determinato numero di secondi


148

Ho una funzione specifica che voglio eseguire dopo 5 secondi. Come posso farlo in Java?

Ho trovato javax.swing.timer, ma non riesco davvero a capire come usarlo. Sembra che io stia cercando qualcosa di molto più semplice di quello che offre questa classe.

Aggiungi un semplice esempio di utilizzo.


Vuoi aspettare 5 secondi e quindi eseguire qualcosa o vuoi continuare a fare qualcos'altro nei 5 secondi?
whiskeysierra,

Voglio continuare a fare qualcosa di diverso
UFK

Risposte:


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

MODIFICARE:

Javadoc dice:

Dopo che l'ultimo riferimento attivo a un oggetto Timer scompare e tutte le attività in sospeso hanno completato l'esecuzione, il thread di esecuzione dell'attività del timer termina in modo corretto (e diventa soggetto alla garbage collection). Tuttavia, ciò può richiedere arbitrariamente molto tempo.


1
Se esegui quel codice, perderai i thread. Assicurati di ripulire il timer quando hai finito.
Skaffman,

1
@skaffman: ho aggiunto una dichiarazione dal javadoc. Devi davvero ripulire dopo aver chiamato il programma?
Tangens,

1
Potrebbe essere OK, ma potrebbe non esserlo. Se esegui quel frammento di codice più volte, avrai a disposizione discussioni libere senza alcun mezzo per riordinarle.
Skaffman,

5
import java.util.Timer; import java.util.TimerTask;potrebbe rendere più ovvio che non lo è javax.swing.Timer. / Nota, se stai usando Swing (e in realtà AWT) non dovresti fare nulla per cambiare componenti su thread EDT (non Dispatch Thread) ( java.util.Timerattività sbagliate; javax.swing.Timerazioni buone).
Tom Hawtin - tackline il

2
@PaulAlexander Secondo i documenti, chiamare il cancelmetodo del timer alla fine del metodo di esecuzione chiarirebbe il thread di esecuzione di TimerTasks.
Dandalf,

58

Qualcosa come questo:

// 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();

Esistono invece altri metodi di fabbrica su Executorcui è possibile utilizzare, se si desidera più thread nel pool.

E ricorda, è importante spegnere l'esecutore quando hai finito. Il shutdown()metodo arresta in modo pulito il pool di thread al termine dell'ultima attività e lo bloccherà fino a quando ciò non accadrà. shutdownNow()terminerà immediatamente il pool di thread.


24

Esempio di utilizzo 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!

Questo codice verrà eseguito una sola volta e l'esecuzione avverrà in 3000 ms (3 secondi).

Come menziona Camickr, dovresti cercare " Come utilizzare i timer di rotazione " per una breve introduzione.


6

Il mio codice è il seguente:

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 
);

5

Come variazione della risposta di @tangens: se non puoi aspettare che il garbage collector ripulisca il tuo thread, annulla il timer alla fine del tuo metodo di esecuzione.

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 
);

Non dovrebbe Timer tessere dichiarato finaldal momento che si accede all'interno di una classe interna?
Joshua Pinter

1
@JoshuaPinter Sì, dovrebbe essere dichiarato final ma non deve essere dichiarato esplicitamente final almeno in Java 8. Deve solo essere "effettivamente final" ( javarevisited.blogspot.com/2015/03/… )
Dandalf

4

La tua domanda originale menziona il "Swing Timer". Se in realtà la tua domanda è relativa a SWing, allora dovresti usare Swing Timer e NON util. Timer.

Leggi la sezione del tutorial Swing su " Come usare i timer " per maggiori informazioni.


4

potresti usare la funzione Thread.Sleep ()

Thread.sleep(4000);
myfunction();

La tua funzione verrà eseguita dopo 4 secondi. Tuttavia, ciò potrebbe mettere in pausa l'intero programma ...


E garantisce solo che l'esecuzione verrà eseguita dopo 4 secondi, il che potrebbe significare anche dopo 10 secondi!
questzen,

2
questzen, scoprirai che tutti i metodi qui lo fanno. In effetti, anche se stai programmando qualcosa a livello di sistema operativo, in genere puoi garantire solo un tempo minimo trascorso prima di un evento.
Ethan,

Questa non è la vera domanda
Inder R Singh,

Ho solo dovuto dare un voto negativo, per niente una risposta alla domanda in corso.
theMayer

OP ha detto in un commento "Voglio continuare a fare qualcos'altro"; questo codice ovviamente no.
Abhijit Sarkar,

3

ScheduledThreadPoolExecutor ha questa capacità, ma è piuttosto pesante.

Timer ha anche questa capacità ma apre diversi thread anche se usato una sola volta.

Ecco una semplice implementazione con un test (firma vicino a Handler.postDelayed () di 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();
    }
}

Test:

@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());
}

dà il sonno di avvertimento chiamato in un ciclo
shareef

Il whileè solo per ignorare interruzione.
AlikElzin-Kilaka,

2

Tutti gli altri unswer richiedono l'esecuzione del codice all'interno di un nuovo thread. In alcuni semplici casi d'uso potresti voler solo aspettare un po 'e continuare l'esecuzione all'interno dello stesso thread / flusso.

Il codice seguente mostra questa tecnica. Tieni presente che è simile a quello che fa java.util.Timer sotto il cofano, ma più leggero.

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());
    }
}

DelayUtil Implementation

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();
        }
    }
}

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);
        }
    }

2
Mentre questo codice può rispondere alla domanda, fornendo ulteriore contesto riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
Mateus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.