web-dev-qa-db-fra.com

Exécuter du code pendant x secondes en Java?

Je voudrais écrire une boucle Java while qui itérera pendant 15 secondes. Une façon pour moi de le faire serait de stocker l'heure système actuelle + 15sec, puis de la comparer au courant temps dans la signature de boucle while.

Y a-t-il une meilleure façon?

27
Danny King

La conception de cela dépend de ce que vous voulez faire pendant 15 secondes. Les deux cas les plus plausibles sont "faites cela tous les X pendant 15 secondes" ou "attendez que X se produise ou 15 secondes selon la première éventualité", ce qui conduira à un code très différent.

J'attends juste

Thread.sleep (15000)

Cela n'itère pas, mais si vous ne voulez rien faire pendant 15 secondes, c'est beaucoup plus efficace (cela gaspille moins de CPU en ne faisant rien).

Répétez du code pendant 15 secondes

Si vous voulez vraiment faire une boucle pendant 15 secondes, votre solution est très bien, tant que votre code ne prend pas trop de temps. Quelque chose comme:

long t= System.currentTimeMillis();
long end = t+15000;
while(System.currentTimeMillis() < end) {
  // do something
  // pause to avoid churning
  Thread.sleep( xxx );
}

Attendez 15 secondes ou une autre condition

Si vous voulez que votre code soit interrompu après exactement 15 secondes quoi qu'il fasse, vous aurez besoin d'une solution multi-thread. Regardez Java.util.concurrent pour de nombreux objets utiles. La plupart des méthodes qui se verrouillent (comme wait ()) ont un argument timeout. Un sémaphore pourrait faire exactement ce dont vous avez besoin.

54
Nick Fortescue

Comme déjà mentionné par d'autres affiches, si vous voulez simplement que le fil se mette en pause pendant un certain temps, utilisez Thread.sleep().

Si vous voulez que le thread fasse quelque chose, mais que vous voulez qu'il s'arrête après un certain temps, utilisez quelque chose comme:

class Foo implements Runnable {
    private volatile boolean killed = false;

    public void run() {
        while (!killed) {
            try { doOnce(); } catch (InterruptedException ex) { killed = true; }
        }
    }

    public void kill() { killed = true; }
    private void doOnce() throws InterruptedException { /* .. */ }
}

et à partir du fil principal, faites:

Foo foo = new Foo(); 
Thread thread = new Thread(foo);
thread.start();

/* when you want to stop it */
foo.kill();
thread.interrupt();
4
Binil Thomas

essaye ça:

public class SleepMessages {
    public static void main(String args[]) throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };

        for (int i = 0; i < importantInfo.length; i++) {
            //Pause for 15 seconds
            Thread.sleep(15000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}

plus d'informations: ici

3
Michel Gokan

Votre approche générale semble correcte bien que vous souhaitiez peut-être voir si l'heure actuelle est supérieure au point que vous souhaitez arrêter, sinon vous risquez de courir pendant une longue période.

L'alternative consiste à exécuter un minuteur/thread qui définit un indicateur après 15 secondes. Cet indicateur devrait être marqué comme volatile sinon votre boucle pourrait ne pas voir le changement se produire dans la valeur.

Le choix si vous vous souciez de l'efficacité est celui qui est le plus cher, obtenir l'heure du système une fois par boucle ou accéder à une variable volatile? Je ne sais pas lequel est le plus efficace - vous pouvez le comparer si c'est vraiment important.

Pour un code simple et maintenable, je choisirais l'approche de vérification de la minuterie:

long endTime = System.currentTimeMillis() + 15000
while (System.currentTimeMillis() < endTime) {
  //loop
} 
2
Robert Christie

Vous pouvez utiliser AOP et une annotation @Timeable de jcabi-aspects (Je suis développeur):

@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
  // do this check regularly:
  if (Thread.currentThread.isInterrupted()) {
    throw new IllegalStateException("time out");
  }
  // execution as normal
}

Lorsque la limite de temps est atteinte, votre thread recevra l'indicateur interrupted() défini sur true et c'est votre travail de gérer correctement cette situation et d'arrêter l'exécution.

1
yegor256

Voici ma suggestion et ça marche bien pour moi :)

StoppingTime = 15 ;
int loop = 1;
long StartTime = System.currentTimeMillis() / 1000 ;
for (int i=0; i<loop; ++i) {
    // your code here

    loop++;
    if (((System.currentTimeMillis()/1000) - StartTime) > StoppingTime)
        loop=0;
}
1
Ghassen Bellagha

Pour l'approche Java.util.concurrent , reportez-vous à Chapitre 6 de Java Concurrence en pratique (section 6.3.7 Placement de limites de temps sur tâches, page 131).

Exemple de code: Récupération d'une annonce avec un budget temps.

0
Steven G. Brown

Une solution similaire à @Tom Hawtin sans taille de boucle arbitraire.

final long end = System.nanoTime() + 15 * 1000 * 1000 * 1000L;
int loop = 1;
do {
    for (int i=0; i<loop; ++i) {
        ...
    }
    loop++;
} while (System.nanoTime() < end);

Dans ce cas, la taille de la boucle intérieure commencera petit mais augmentera de taille si la boucle est particulièrement rapide. S'il est suffisamment lent, il ne peut être répété qu'une seule fois.

0
Peter Lawrey

En supposant que vous vouliez que la boucle fasse quelque chose de sensé, vous pourriez trouver plus rapide de vérifier un indicateur volatile. Demandez à un autre thread d'attendre 15 secondes (ou utilisez une minuterie), puis réglez-le.

Alternativement, si vous savez à peu près combien de temps le corps de la boucle prendra, exécutez-le plusieurs centaines de fois, par exemple, et vérifiez l'heure dans une boucle externe.

final long start = System.nanoTime();
do {
    for (int i=0; i<200, ++i) {
        ...
    }
} while (System.nanoTime()-start < 15L*1000L*1000L*1000L);

System.nanoTimedevrait ne pas être dérouté par les changements d'horloge système. L'utilisation de longs nombres littéraux est importante.

0

Vous pourriez être intéressé par la planification d'une TimerTask qui arrête un autre thread ou modifie la condition de votre boucle.

0
YuppieNetworking

Ne vérifiez jamais l'heure actuelle dans une boucle serrée.

Sinon, quelqu'un avec un ordinateur portable peut se faire brûler les genoux par un processeur surchauffé. J'ai entendu les histoires de ce qui s'est réellement passé.

0

Je vous suggère de le faire avec la classe timer en évitant Thread.sleep (xxx); méthode.

par exemple:

import Java.util.Timer;
import Java.util.TimerTask;

public class TimerExample {
    private int globalTimer = 0;
    private int limitTimer = 15;

    public static void main(String[] args) {
        new TimerExample();
    }

    public TimerExample() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                globalTimer++;
                // DO YOUR CODE HERE
                System.out.println("running");
                if (globalTimer == limitTimer) {
                    timer.cancel();
                }
            }
        }, 0, 1000);
    }
}
0
theo231022