美国上市公司,专注Java培训22年

如何使按秒输出当前时间的程序不跳秒


学习线程的时候,达内java培训的传奇老师带我们做了一个按秒显示当前时间的小程序。这个程序不难,
但传奇老师课上提到这个小程序有缺陷,就是你仔细盯着输出结果看,有时候会发现显示
的时间突然跳了一秒,比如从19:56:42 跳到19:56:44。
我对这个现象产生的原因很感兴趣,于是研究了一下它是如何产生的以及研究了一下解决办法。
原程序如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class ThreadDemo8 {

/**
* @param args
*/
public static void main(String[] args) {
/*
* 实现电子表功能
* 每秒钟输出依次当前系统时间
* HH:mm:ss
*/
Thread t=new Thread(){
public void run(){
Calendar calendar;
Date date;
String str;
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
for(;;){
calendar=Calendar.getInstance();
calendar.add(calendar.HOUR_OF_DAY, 16);
calendar.add(calendar.MINUTE, 4);
date=calendar.getTime();
str=sdf.format(date);
System.out.println(str+" ");//输出当前时间
try{
Thread.sleep(1000);
}catch(InterruptedException e){
}
}
}
};
t.start();
}
}

为了使时间显示的更精确,我将用于输出当前时间的 System.out.println(str+" ");
这句改为了 System.out.println(str+" "+System.currentTimeMillis()%1000);
输出结果如下:
20:09:43 998
20:09:44 998
20:09:45 998
20:09:46 999
20:09:47 999
20:09:48 999
20:09:49 999
20:09:50 999
20:09:52 0
20:09:53 0
20:09:54 0
20:09:55 0
20:09:56 1
20:09:57 1
20:09:58 1
20:09:59 1
20:10:00 2
20:10:01 2
20:10:02 2

可以发现,在20:09:50到20:09:52发生了跳跃,把20:09:51隔过去了。还能发现大约每数4.4次,
毫秒数会+1,也就是每4.4*1000=4400次即73分钟会跳一次秒。这是不是很像每天比实际地球自转
时间多算约4分钟,所以每4年要多1天来抵消这个误差?这个计时程序的误差来自
Thread.sleep(1000); 这里没有把计算机运行一次for循环所用的时间考虑进去。所以,它应
该sleep更少的时间才对,大约少sleep 1/4.4毫秒。
于是,我就像用增加润年的方法把
Thread.sleep(1000); 改为:
Thread.sleep(1000-i%5/4+i%40/39); //每5毫秒减少1毫秒,每40毫秒增加1毫秒
它的输出结果变成这样了
20:25:36 393
20:25:37 393
20:25:38 394
20:25:39 394
20:25:40 394
20:25:41 393
20:25:42 393
20:25:43 394
20:25:44 394
20:25:45 394
20:25:46 393
20:25:47 394
20:25:48 394
误差小了很多,但是还是不够精确。就像我们现实的时间虽有润年调整,还是无法和地球自转时间对照,
因此前几年有2天都出现了如19:59:60这样时间,增加1秒以对地球的计时做校正。
但是,在这个程序中我们可以抛弃这种永远无法真正校准时间的方法。我想起了原来我学过的一门课程
《自动控制原理》,里面有个概念叫做负反馈,根据结果来校正下一次的结果可以做到真正的精准。
用在这里具体就是:输出的时间超了1毫秒就在下次减1毫秒,超2毫秒就减2毫秒。反正它能自动调整为
准确时间
于是有了如下方法:
Thread.sleep(1000); 改为:
Thread.sleep(1000-System.currentTimeMillis()%1000);
输出结果如下:
20:32:32 0
20:32:33 0
20:32:34 0
20:32:35 0
20:32:36 0
20:32:37 0
20:32:38 0
可以发现,这次的输出时间都是和系统几乎同步的!做到了真正的精准。最终版本的程序如下:


import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class ThreadDemo8 {

/**
* @param args
*/
public static void main(String[] args) {
/*
* 实现电子表功能
* 每秒钟输出依次当前系统时间
* HH:mm:ss
*/
Thread t=new Thread(){
public void run(){
Calendar calendar;
Date date;
String str;
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
for(int i=0;;i++){
calendar=Calendar.getInstance();
calendar.add(calendar.HOUR_OF_DAY, 16);
calendar.add(calendar.MINUTE, 4);
date=calendar.getTime();
str=sdf.format(date);
if(i>0){
System.out.println(str+" "+System.currentTimeMillis()%1000);
}
try{
Thread.sleep(1000-System.currentTimeMillis()%1000);
}catch(InterruptedException e){
}
}
}
};
t.start();
}

}


【免责声明】本文部分系转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,如涉及作品内容、版权和其它问题,请在30日内与我们联系,我们会予以重改或删除相关文章,以保证您的权益!

Java开发高端课程免费试学

大咖讲师+项目实战全面提升你的职场竞争力

  • 海量实战教程
  • 1V1答疑解惑
  • 行业动态分析
  • 大神学习路径图

相关推荐

更多
  • 达内java培训学员分享:论数学公式在编程中的应用
    达内java培训学员分享:论数学公式在编程中的应用
    本文转载达内java培训学员学习心得。 详情>>

    2015-10-13

  • 讲解2种查找素数的方法
    讲解2种查找素数的方法
    达内java培训学员讲解2种查找素数的方法 详情>>

    2015-10-13

  • 一个俄罗斯方块程序(非案例版)
    一个俄罗斯方块程序(非案例版)
    我们学面向对象的时候曾经做过俄罗斯方块这个案例,当时没有做完,我也不知道有《JAVA经典项目集锦》这个教材(做飞机大战的时候老师才告诉我们有这个书)。我当时想把它完成,可是自己又水平不够,不会JFrame,不会操纵图片,不会定时器,不会监听键盘,感觉难以下手。所以我在网上找了一个别人做的俄罗斯方块程序,把它小幅修改了一下,分享给大家。 详情>>

    2015-10-13

  • 用java模拟光的单缝衍射和牛顿环
    用java模拟光的单缝衍射和牛顿环
    使用java做出模拟光的单缝衍射和牛顿环的图案。 详情>>

    2015-09-21

  • Java开班时间

    收起