Java循环持续一段时间
有没有办法可以轻松地在一段时间内进行for循环? (没有使用System.currentTimeMillis()测量自己的时间?)
即我想在Java中做这样的事情:
int x = 0; for( 2 minutes ) { System.out.println(x++); }
谢谢
不,没有内置的构造可以做到这一点。
我想指出,您不应该使用System.currentTimeMillis()在指定的时间段内执行或延迟任务。 而是使用System.nanoTime()。 前一种方法在Windows中不准确,而后一种方法无论操作系统如何都是准确的。 您可以使用TimeUnit枚举轻松地在毫秒或任何其他时间单位之间的时间内以毫秒为单位。
for (long stop=System.nanoTime()+TimeUnit.SECONDS.toNanos(2);stop>System.nanoTime();) { /* * Hammer the JVM with junk */ }
我认为这就是你想要的:
private final Thread thisThread = Thread.current(); private final int timeToRun = 120000; // 2 minutes; new Thread(new Runnable() { public void run() { sleep(timeToRun); thisThread.interrupt(); } }).start(); while (!Thread.interrupted()) { // do something interesting. }
这避免了重复的系统调用来获取系统时钟值(这可能相当昂贵)并且轮询当前线程的interrupted
标志(更便宜)。
编辑
实际上,没有安全的选择来轮询时钟或轮询标志。 理论上,您可以修改上面的片段来调用弃用的 Thread.stop()
方法而不是Thread.interrupt()
。
(我不建议使用Thread.stop()
和朋友。它们有缺陷,而且使用起来很危险。我只是把它作为理论选择。)
编辑2
只是要指出使用Thread.interrupt()
比设置共享标志更有优势:
-
Thread.interrupt()将导致某些阻塞I / O和同步方法解除阻塞并抛出已检查的exception。 更新共享标志不会这样做。
-
某些第三方库还检查中断标志,以查看它们是否应该停止它们当前正在执行的操作。
-
如果你的循环涉及对其他方法的调用等,Thread.interrupt()意味着你不必担心这些方法可以访问标志……如果需要的话。
编辑3
只是补充一点, sleep(N)
不能保证在N
毫秒后唤醒睡眠线程。 但在正常情况下,它会相当接近。
我为这个问题做了一个简单但很糟糕的实现。 我想避免使用Timer和TimeTask,最终得到了这个quickfix解决方案。
主要的想法是我只想创建一个独立倒计时器,我可以启动它并调用isFinished()来检查倒计时是否完成。
package RIPv3; /** * Creates a countdown timer which runs its own thread and uses CountdownTimerThread, which runs yet another * thread. * * start() method is called to start the countdown. * isFinished() method is called to check if the countdown is finished or not. * * ! Be Aware! * This is a quickfix and sucky implementation. * There will be a small delay. This is not accurate. * * @author Endre Vestbø * @version 1.0 (09.05.2011) */ public class CountdownTimer extends Thread { /* Countdown timer */ private CountdownTimerThread timer; /** * Creates a new timer and sets time to count down * @param time * Time to count down */ public CountdownTimer(long time) { this.timer = new CountdownTimerThread(time); } public void run() { this.timer.start(); } /** * @return * False if timer is running, else true */ public boolean isFinished() { if(this.timer.getState() == Thread.State.TERMINATED) return true; return false; } }
package RIPv3; /** * Used by CountdownTimer to count down time. * * @author Endre Vestbø * @version 1.0 (09.05.2011) * */ public class CountdownTimerThread extends Thread { private long time; /** Create a new timer */ public CountdownTimerThread(long time) { this.time = time; } /** * Start a countdown * @param period * Period to count down given in milliseconds */ public void run() { try { sleep(this.time); } catch (InterruptedException e) { } } }
这是另一个建议:
公共类TimerLoop { private final AtomicBoolean loop = new AtomicBoolean();
public void run(Runnable runnable, long duration, TimeUnit timeUnit) { loop.set(true); TimerTask task = new TimerTask() { @Override public void run() { loop.set(false); } }; Timer timer = new Timer(); timer.schedule(task, timeUnit.toMillis(duration)); while (loop.get()) { runnable.run(); } }
}
该方法重复执行所提供的Runnable
的run()
方法,直到计时器到期。
注意事项:
- 时间是近似的。
- 请注意如何实现
run()
方法,因为它可能会占用您的所有CPU功率。 - 除非您为要执行的每个
Runnable
创建TimerLoop
类的新实例,否则该实现不是线程安全的。
没有。考虑到简单地编写一个使用System.currentTimeMillis()(或者你选择的任何时间函数)的函数是多么简单,这是一个奇怪的请求。 情况的更多背景可能是有序的。
我不认为有一种方法可以循环一段时间而不检查你是否已经循环了一段时间。
根据你的用例, Thread类中的两个sleep()方法中的任何一个都可能符合要求,但听起来你必须对System.currentTimeMillis()大惊小怪,这看起来很奇怪。
Thread thread = Thread.currentThread(); thread.sleep(10); // 10 milliseconds thread.sleep(12, 345); // 12 milliseconds and 345 nanoseconds.
循环迭代值比较而不是持续时间。 因此,如果没有自己分配和比较系统时间,你就无法做到。 如果你希望它是直观的,那么你可以拥有一个内部使用毫秒的函数,但是将Minutes作为参数并使用它。
不,你不能在其中使用线程或睡眠方法,因为这不能确保准确的时间。 如果处理器在给定时间过后忙于某个其他线程,那么您的线程将继续等待。