Java 等待系统时间以继续应用程序

Java 等待系统时间以继续应用程序,java,datetime,calendar,blocking,busy-waiting,Java,Datetime,Calendar,Blocking,Busy Waiting,我已经编写了一个类,如果当前秒数是5的倍数(即Calender.second%5==0),则继续启动JAVA应用程序 下面给出了类代码,我好奇的是,我这样做对吗?这似乎不是一个优雅的解决方案,像这样阻止执行并一次又一次地获取实例 public class Synchronizer{ private static Calendar c; public static void timeInSync(){ do{ c = Calendar.ge

我已经编写了一个类,如果当前秒数是5的倍数(即Calender.second%5==0),则继续启动JAVA应用程序

下面给出了类代码,我好奇的是,我这样做对吗?这似乎不是一个优雅的解决方案,像这样阻止执行并一次又一次地获取实例

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
...

正如@ChrisK所建议的,只需直接调用
System.currentTimeMillis()
即可简化

例如:

    long time = 0;
    do
    {
        time = System.currentTimeMillis();

    } while (time % 5000 != 0);
请注意,您需要将比较值更改为5000,因为时间的表示形式是以毫秒为单位的

此外,像这样直接进行任何比较都可能存在陷阱,因为循环调用取决于处理器可用性等等,所以这样的实现有可能进行一次调用,返回:

`1411482384999`
然后循环中的下一个调用返回

`1411482385001`
这意味着由于硬件可用性,您的条件已被跳过


如果您想使用内置的调度程序,我建议您在这里查看类似问题的答案,正如@ChrisK建议的那样,您可以通过直接调用
System.currentTimeMillis()
来简化

例如:

    long time = 0;
    do
    {
        time = System.currentTimeMillis();

    } while (time % 5000 != 0);
请注意,您需要将比较值更改为5000,因为时间的表示形式是以毫秒为单位的

此外,像这样直接进行任何比较都可能存在陷阱,因为循环调用取决于处理器可用性等等,所以这样的实现有可能进行一次调用,返回:

`1411482384999`
然后循环中的下一个调用返回

`1411482385001`
这意味着由于硬件可用性,您的条件已被跳过

如果您想使用内置的调度程序,我建议您在这里查看类似问题的答案

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();
        }    
    }
}
公共类同步器
{
公共静态void timeInSync()
{
long lastnotime=System.nanoTime();
long nowTime=System.nanoTime();
而(nowTime/1000000-lastNanoTime/1000000<5000)
{
nowTime=System.nanoTime();
}    
}
}
您应该使用

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();
        }    
    }
}
公共类同步器
{
公共静态void timeInSync()
{
long lastnotime=System.nanoTime();
long nowTime=System.nanoTime();
而(nowTime/1000000-lastNanoTime/1000000<5000)
{
nowTime=System.nanoTime();
}    
}
}

您现在拥有的是所谓的忙等待(有时也称为轮询),是的,它在处理器使用和能源使用方面效率低下。只要操作系统允许,代码就会执行,这样做会阻止CPU用于其他工作,或者当没有其他工作时,会阻止CPU打盹,浪费能源(加热CPU,耗尽电池…)

你应该做的是让你的线程进入睡眠状态,直到你想做某事的时间到来。这允许CPU执行其他任务或进入睡眠状态

java.lang.Thread上有一个方法可以做到这一点:
Thread.sleep(长毫秒)
(它也有一个表兄接受一个额外的nanos参数,但是VM可能会忽略nanos,并且很少需要这种精度)

所以首先你要确定什么时候需要做一些工作。然后你一直睡到那时。一个简单的实现可能是这样的:

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);
    }
}
publicstaticvoidwaituntil(长时间戳){
long millis=时间戳-System.currentTimeMillis();
//如果时间已经过去,请立即返回

if(millis您现在拥有的称为忙等待(有时也称为轮询),是的,它在处理器使用和能源使用方面效率低下。只要操作系统允许,代码就会执行,这样做会阻止CPU用于其他工作,或者在没有其他工作时,会阻止CPU打盹,浪费能源(加热CPU,耗尽电池…)

你应该做的是让你的线程进入睡眠状态,直到你想做的事情到来。这允许CPU执行其他任务或进入睡眠状态

java.lang.Thread上有一个方法可以做到这一点:
Thread.sleep(长毫秒)
(它也有一个表兄接受一个额外的nanos参数,但是VM可能会忽略nanos,并且很少需要这种精度)

因此,首先确定什么时候需要做一些工作,然后再睡到那个时候。一个简单的实现可能是这样的:

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);
    }
}
publicstaticvoidwaituntil(长时间戳){
long millis=时间戳-System.currentTimeMillis();
//如果时间已经过去,请立即返回

if(millis第一个要点是,您永远不能使用忙等待。在java中,您可以通过使用
Object.wait(timeout)
Thread.sleep(timeout)
来避免忙等待。后者更适合您的情况,因为您的情况不需要丢失监视器锁

接下来,您可以使用两种方法来