java: exécuter une fonction après un certain nombre de secondes

148

J'ai une fonction spécifique que je souhaite exécuter après 5 secondes. Comment puis-je faire cela en Java?

J'ai trouvé javax.swing.timer, mais je ne comprends pas vraiment comment l'utiliser. Il semble que je cherche quelque chose de plus simple que ce que cette classe fournit.

Veuillez ajouter un exemple d'utilisation simple.

ufk
la source
Voulez-vous attendre 5 secondes puis exécuter quelque chose ou voulez-vous continuer à faire autre chose dans les 5 secondes?
whiskeysierra
Je veux continuer à faire autre chose
ufk

Réponses:

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

ÉDITER:

javadoc dit:

Une fois que la dernière référence en direct à un objet Timer a disparu et que toutes les tâches en attente ont été exécutées, le thread d'exécution de la tâche du minuteur se termine correctement (et devient soumis au garbage collection). Cependant, cela peut prendre un temps arbitraire à se produire.

tangens
la source
1
Si vous exécutez ce code, vous fuirez des threads. Assurez-vous de nettoyer la minuterie lorsque vous avez terminé.
skaffman
1
@skaffman: J'ai ajouté une déclaration du javadoc. Devez-vous vraiment nettoyer après avoir appelé l'horaire?
tangens
1
Cela peut être correct, mais ce n'est peut-être pas le cas. Si vous exécutez ce fragment de code plusieurs fois, vous aurez des threads lâches sans aucun moyen de les ranger.
skaffman
5
import java.util.Timer; import java.util.TimerTask;pourrait rendre plus évident que ce n'est pas le cas javax.swing.Timer. / Remarque, si vous utilisez Swing (et en fait AWT), vous ne devriez rien faire pour changer les composants sur les threads non-Event Dispatch Thread (EDT) ( java.util.Timertâches mauvaises; javax.swing.Timeractions bonnes).
Tom Hawtin - tackline
2
@PaulAlexander Selon la documentation, appeler la cancelméthode du timer à la fin de la méthode run effacerait le thread d'exécution de TimerTasks.
Dandalf
58

Quelque chose comme ça:

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

Il existe diverses autres méthodes d'usine sur Executorlesquelles vous pouvez utiliser à la place, si vous voulez plus de threads dans le pool.

Et rappelez-vous, il est important d'arrêter l'exécuteur testamentaire lorsque vous avez terminé. La shutdown()méthode arrête proprement le pool de threads lorsque la dernière tâche est terminée et se bloque jusqu'à ce que cela se produise. shutdownNow()mettra fin au pool de threads immédiatement.

skaffman
la source
24

Exemple d'utilisation 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!

Ce code ne sera exécuté qu'une seule fois, et l'exécution se produira dans 3000 ms (3 secondes).

Comme le mentionne camickr, vous devriez chercher " Comment utiliser les minuteries de swing " pour une brève introduction.

zpon
la source
6

Mon code est le suivant:

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
la source
5

Comme variante de la réponse @tangens: si vous ne pouvez pas attendre que le garbage collector nettoie votre thread, annulez le minuteur à la fin de votre méthode d'exécution.

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
la source
Ne devrait pas Timer têtre déclaré finalcar on y accède dans une classe interne?
Joshua Pinter
1
@JoshuaPinter Oui, il devrait être déclaré définitif, mais il n'a pas besoin d'être explicitement déclaré définitif dans au moins Java 8. Il doit juste être "effectivement final" ( javarevisited.blogspot.com/2015/03/… )
Dandalf
4

Votre question initiale mentionne le "Swing Timer". Si en fait votre question est liée à SWing, alors vous devriez utiliser le Swing Timer et PAS l'util.Timer.

Lisez la section du didacticiel Swing sur « Comment utiliser les minuteries » pour plus d'informations.

camickr
la source
4

vous pouvez utiliser la fonction Thread.Sleep ()

Thread.sleep(4000);
myfunction();

Votre fonction s'exécutera après 4 secondes. Cependant, cela pourrait mettre en pause tout le programme ...

vallée
la source
Et cela garantit seulement que l'exécution se déroulera après 4 secondes, ce qui pourrait signifier également après 10 secondes!
questzen
2
questzen, vous constaterez que toutes les méthodes ici font cela. En fait, même si vous planifiez quelque chose au niveau du système d'exploitation, vous ne pouvez généralement garantir qu'un temps minimum écoulé avant un événement.
Ethan
Ce n'est pas la vraie question
Inder R Singh
Je devais simplement donner un vote défavorable - pas du tout une réponse à la question en cours.
theMayer
OP a dit dans un commentaire "je veux continuer à faire autre chose"; ce code, évidemment, ne le fait pas.
Abhijit Sarkar
3

ScheduledThreadPoolExecutor a cette capacité, mais c'est assez lourd.

Timer a également cette capacité mais ouvre plusieurs threads même s'il n'est utilisé qu'une seule fois.

Voici une implémentation simple avec un test (signature proche de Handler.postDelayed () ) d'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();
    }
}

Tester:

@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
la source
il donne un sommeil d'avertissement appelé dans une boucle
shareef
Il whiles'agit simplement d'ignorer l'interruption.
AlikElzin-kilaka le
2

Tous les autres unswers nécessitent d'exécuter votre code dans un nouveau thread. Dans certains cas d'utilisation simples, vous pouvez simplement attendre un peu et continuer l'exécution dans le même thread / flux.

Le code ci-dessous illustre cette technique. Gardez à l'esprit que cela est similaire à ce que java.util.Timer fait sous le capot mais plus léger.

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

Implémentation 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
la source
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
la source
2
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
Mateus