等待系统时间继续申请
我已经写了类以继续开始JAVA应用,如果当前第二个是5(即Calender.SECOND%5 == 0)的倍数等待系统时间继续申请
的类代码是如下所示,我很好奇的是,我是否以正确的方式做这件事?它看起来不是一个优雅的解决方案,阻止像这样的执行并反复得到实例。
public class Synchronizer{
private static Calendar c;
public static void timeInSync(){
do{
c = Calendar.getInstance();
}
while(c.get(Calendar.SECOND) % 5 != 0);
}
}
Synchronizer.timeInSync()被调用另一个类的构造函数,并在主方法开始创建该类的实例。然后应用程序永远运行一个每5秒调用一次的TimerTask。
是否有一个更清晰的解决方案来同步时间?
更新:
我觉得我没有明确说明,但是我正在寻找在这里与系统时间同步没有做忙等待。
所以我需要能够得到
12:19:00
12:19:05
12:19:10
...
现在你已经叫什么忙等待(有时也称为轮询),并且是其在处理器的使用方面效率低下,并在能源使用方面。您的代码在操作系统允许时执行,并且这样做可以防止CPU使用其他工作,或者当没有其他工作时,它会阻止CPU休息,浪费能源(加热CPU,耗尽电池电量...)。
你应该做的是把你的线程睡觉,直到你想要做的事情到达的时候。这允许CPU执行其他任务或进入睡眠状态。
java.lang.Thread上有一个方法可以做到这一点:Thread.sleep(long milliseconds)
(它也有一个表弟需要额外的nanos参数,但是nanos可能会被VM忽略,并且这种精度很少需要)。
所以首先你确定当你需要做一些工作。然后你睡到那个时候。一个天真的实现可能看起来像:
public static void waitUntil(long timestamp) {
long millis = timestamp - System.currentTimeMillis();
// return immediately if time is already in the past
if (millis <= 0)
return;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
这工作得很好,如果你没有太严格的要求上精确打击的时候,你可以期望它回到合理地接近规定的时间(几十毫秒如果时间不是太远(几秒钟),那么可能就会离开。然而,你有没有保证,偶尔当操作系统真的很忙,它可能会很晚返回。
稍微更准确的方法是确定reuired睡眠时间,睡眠一半的时间,评估再次所需的睡眠,睡眠再次一半直至所需的睡眠时间变得非常小的时间等,然后,忙等待剩下的几毫秒。
但System.currentTimeMillis()不保证实际的时间分辨率;它每毫秒可能会改变一次,但它可能每十毫秒改变10次(这取决于平台)。 System.nanoTime()也一样。
在多任务环境中(现在几乎所有地方),在高级编程语言中不可能等待准确的时间点。如果您有严格的要求,则需要转到特定操作系统以在指定时间创建中断,并在中断(即汇编程序或至少C代表中断处理程序)中处理事件。在大多数正常的应用中,你不需要这么做,在游戏/应用程序中,几个ms +/-通常无关紧要。
正是我在找的是谢谢。 – ickarsim 2014-09-24 09:26:55
由于@ChrisK建议,可以通过只是让直接调用System.currentTimeMillis()
简化。
例如:
long time = 0;
do
{
time = System.currentTimeMillis();
} while (time % 5000 != 0);
需要注意的是,你需要比较值更改为5000,因为当时的表示是毫秒。
另外,还有一些可能存在的缺陷,以如此直接这样做任何比较,作为循环调用取决于处理器的可用性和诸如此类的东西,所以它返回一个机会,像这样的实现可以使一个电话:
`1411482384999`
然后在环形折返
`1411482385001`
意思是说你的病情已经凭借硬件可用性跳过下一个电话。
如果你想使用一个内置的调度程序,我建议在寻找的答案,在这里java: run a function after a specific number of seconds
了类似的问题,您应该使用的
System.nanoTime()
代替
System.currentTimeMillis()
因为它会返回测量的经过时间而不是系统时间,所以nanoTime不受系统时间变化的影响。
public class Synchronizer
{
public static void timeInSync()
{
long lastNanoTime = System.nanoTime();
long nowTime = System.nanoTime();
while(nowTime/1000000 - lastNanoTime /1000000 < 5000)
{
nowTime = System.nanoTime();
}
}
}
第一个要点是,你绝对不能使用忙等待。在Java中,您可以通过使用Object.wait(timeout)
或Thread.sleep(timeout)
来避免繁忙等待。后者更适合您的情况,因为您的情况不需要丢失显示器锁定。
接下来,您可以使用两种方法等待您的时间条件满足。您可以预先计算整个等待时间,或者等待循环中的小时间间隔,检查条件。
我将在这里说明了这两种方法:
private static long nextWakeTime(long time) {
if (time/1000 % 5 == 0) { // current time is multiple of five seconds
return time;
}
return (time/1000/5 + 1) * 5000;
}
private static void waitUsingCalculatedTime() {
long currentTime = System.currentTimeMillis();
long wakeTime = nextWakeTime(currentTime);
while (currentTime < wakeTime) {
try {
System.out.printf("Current time: %d%n", currentTime);
System.out.printf("Wake time: %d%n", wakeTime);
System.out.printf("Waiting: %d ms%n", wakeTime - currentTime);
Thread.sleep(wakeTime - currentTime);
} catch (InterruptedException e) {
// ignore
}
currentTime = System.currentTimeMillis();
}
}
private static void waitUsingSmallTime() {
while (System.currentTimeMillis()/1000 % 5 != 0) {
try {
System.out.printf("Current time: %d%n", System.currentTimeMillis());
Thread.sleep(100);
} catch (InterruptedException e) {
// ignore
}
}
}
正如你可以看到,等待预先计算的时间是比较复杂的,但它更精确,更有效的(因为在一般情况下,它会做单次迭代)。迭代等待小时间间隔更简单,但效率更低,精度更高(精度取决于所选时间间隔的大小)。
同时请注意,我如何计算,如果时间条件满足:
(time/1000 % 5 == 0)
在你需要计算到秒,然后才检查多个五个第一步。检查正如其他答案中所建议的那样是错误的,因为只有在每第五秒的第一毫秒时才是正确的。time % 5000 == 0
您是否熟悉System.currentTimeMillis? – 2014-09-23 14:22:38
您也可以使用[定时器](http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html),因为这是它的设计目的。 – Compass 2014-09-23 17:42:09
我已经更新了一个更清晰问题的问题,但杜兰达的解释性答案对我来说非常满意。 – ickarsim 2014-09-24 09:26:25