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?
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.
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).
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 );
}
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.
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();
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
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
}
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.
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;
}
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.
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.
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.nanoTime
devrait ne pas être dérouté par les changements d'horloge système. L'utilisation de longs nombres littéraux est importante.
Vous pourriez être intéressé par la planification d'une TimerTask qui arrête un autre thread ou modifie la condition de votre boucle.
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é.
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);
}
}