有没有一种简单的方法可以在特定时间内执行for循环?(不使用System.currentTimeMillis()来计算时间)
例如,我想在Java中像这样做:
int x = 0;
for( 2 minutes ) {
System.out.println(x++);
}
谢谢
有没有一种简单的方法可以在特定时间内执行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
*/
}
nanoTime()
,System.currentTimeMillis()
的精度较低,但仍然有约10-15毫秒。因此,除非您想测量在毫秒范围内的时间,否则使用 System.currentTimeMillis()
完全没有问题。此外,我认为 System.currentTimeMillis()
比 nanoTime()
稍微快一些(尽管这取决于 JVM,通常不会产生差异)。 - sleskeTimeUnit.SECONDS
枚举所规定。请参阅:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/TimeUnit.html - Tim Benderprivate 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和同步方法取消阻塞并抛出已检查异常。更新共享标志无法做到这一点。
某些第三方库还会检查中断标志以查看它们是否应该停止当前正在执行的操作。
如果您的循环涉及调用其他方法等,则Thread.interrupt()
意味着您不需要担心这些方法可以访问标志......如果它们需要。
编辑3
仅补充说明sleep(N)
不能保证在N
毫秒后唤醒正在睡眠的线程。但在正常情况下,它会相当接近。
我为这个问题做了一个简单但不太好的实现。我想避免使用Timer和TimeTask,结果用了这个临时解决方案。
主要思路是我只想创建一个独立的倒计时器,可以随时启动并调用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) {
}
}
}
这里有另一个建议:
public class 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()
可能会非常昂贵。在某些平台上,它将涉及进行系统调用;即数百条机器指令。 - Stephen CLocalDateTime then = LocalDateTime.now();
while (true) {
// logic
if (ChronoUnit.SECONDS.between(then, LocalDateTime.now()) >= 20) break;
}
我认为没有一种方法可以在不检查是否已经循环了一定时间的情况下循环一段时间。
sleep
系统调用与时间有关。但是机制不在ScheduledFuture
等代码内部,而是在操作系统内核中。它绝对不涉及“检查是否已循环一定时间”。 - Stephen CThread thread = Thread.currentThread();
thread.sleep(10); // 10 milliseconds
thread.sleep(12, 345); // 12 milliseconds and 345 nanoseconds.
循环是基于值比较,而不是持续时间。因此,如果你不自己分配和比较系统时间,就无法实现这一点。 然而,如果你希望它直观一些,那么可以有一个内部使用毫秒的函数,但以分钟为参数并使用它。
并且,不,你不能在其中使用线程或sleep方法,因为那不能确保精确的时间。如果在给定时间过后你的处理器忙于其他线程,那么你的线程将继续等待。