您当前的位置:首页 > 计算机 > 编程开发 > Java

Java整点报时定时器

时间:02-09来源:作者:点击数:

今天在改一个开源SpringBoot项目,要拿到Android中使用,所以要去除掉SpringBoot相关的东西,看到项目中使用了SpringBoot的@Scheduled(cron = "0 0 * * * ?")来添加定时器,非常简洁,就这么一个注解就实现了整点执行,每一个小时的整点执行,我要改到Android中去用,Android中不知道怎么使用Spring的注解,所以我就不用Spring,改成普通的Java代码实现。

一个整时执行一次,这样等待的时间太长了,所以我先实现一整秒执行一次,方便测试。使用Timer即可轻松实现,如下:

timer.scheduleAtFixedRate(task, firstTime, period);

如果是整点,假如现在是10:23分,则需要在11:00执行定时器,所以关键点在于拿到下一个小时,如果是整秒,则是拿到下一秒,代码如下:

static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

public static Date getNextHour() {
    Calendar calendar = Calendar.getInstance();
    System.out.println("当前时间 = " + dateFormat.format(calendar.getTime()));    
    
    calendar.set(Calendar.MILLISECOND, 0); 	// 清空毫秒
    calendar.add(Calendar.SECOND, 1);		// 添加一秒
    
    Date nextHour = calendar.getTime();
    System.out.println("开始时间 = " + dateFormat.format(nextHour));
    return nextHour;
}

运行getNextHour()函数,打印结果如下:

当前时间 = 2022-07-11 16:01:50.294
开始时间 = 2022-07-11 16:01:51.000

OK,成功的获取到了下一个整秒,然后就是使用定时器,从下一整秒开始,每隔一秒执行一次:

public static void main(String[] args) {
    Timer timer = new Timer();
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            System.out.println(dateFormat.format(new Date()));
        }
    };
    Date firstTime = getNextHour();				// 设置定时器第1次执行的开始时间
    long period = TimeUnit.SECONDS.toMillis(1); // 设置每隔1秒执行1次
    timer.scheduleAtFixedRate(task, firstTime, period);
}

执行效果如下:

当前时间 = 2022-07-11 16:07:15.570
开始时间 = 2022-07-11 16:07:16.000
2022-07-11 16:07:16.010
2022-07-11 16:07:17.011
2022-07-11 16:07:18.010
2022-07-11 16:07:19.010
2022-07-11 16:07:20.005
2022-07-11 16:07:21.005

可以看到定时器并不是百分百准时的,我们设置的是在16:07:16.000执行,但却是在16:07:16.010执行,有10毫秒的偏差,往后是每隔一秒执行一次,也是有毫秒级的偏差的,像航天航空这种高精度要求的,肯定用不了这种定时器,而对于我们的普通应用,这点影响一般是无关紧要的。

另外,在开始解这个问题的时候,开始时间弄错了,导致发现一个定时器的Bug,比如当前时间已经是15秒了,你却设置为12秒的时候执行,慢了3秒,则一运行代码就会立马执行4次run()函数(为什么不是3次?我也不知道,反正慢4秒就执行5次,慢5秒就执行6次,就这个规律),示例如下:

把设置秒的地方设置为负3秒,如下:

calendar.add(Calendar.SECOND, -3);

运行效果如下:

当前时间 = 2022-07-11 16:14:26.325
开始时间 = 2022-07-11 16:14:23.000
2022-07-11 16:14:26.340
2022-07-11 16:14:26.340
2022-07-11 16:14:26.340
2022-07-11 16:14:26.340
2022-07-11 16:14:27.012
2022-07-11 16:14:28.012

所以,定时器的开始时间不能弄错,不能设置的比当前时间早,设置的早了就会出现这样的问题。

实现了整秒的定时器,再实现整点的定时器就很简单了,代码如下:

static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

public static void main(String[] args) {
    Timer timer = new Timer();
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            System.out.println(dateFormat.format(new Date()));
        }
    };
    Date firstTime = getNextHour();				// 设置定时器第1次执行的开始时间
    long period = TimeUnit.HOURS.toMillis(1);	// 设置每隔1小时执行1次		
    timer.scheduleAtFixedRate(task, firstTime, period);	
}

/** 获取当前时间的下一个小时的整点时间 */
public static Date getNextHour() {
    Calendar calendar = Calendar.getInstance();
    System.out.println("当前时间 = " + dateFormat.format(calendar.getTime()));
    
    calendar.set(Calendar.MINUTE, 0);       // 清空分
    calendar.set(Calendar.SECOND, 0);       // 清空秒
    calendar.set(Calendar.MILLISECOND, 0);  // 清空毫秒
    calendar.add(Calendar.HOUR, 1); 		// 添加1小时
    
    Date nextHour = calendar.getTime();
    System.out.println("开始时间 = " + dateFormat.format(nextHour));
    return nextHour;
}

执行效果如下:

当前时间 = 2022-07-11 16:24:56.510
开始时间 = 2022-07-11 17:00:00.000
2022-07-11 17:00:00.013
2022-07-11 18:00:00.006
2022-07-11 19:00:00.009
2022-07-11 20:00:00.011
2022-07-11 21:00:00.001
2022-07-11 22:00:00.005
2022-07-11 23:00:00.009
2022-07-12 00:00:00.014
2022-07-12 01:00:00.018
2022-07-12 02:00:00.004
2022-07-12 03:00:01.233
2022-07-12 04:00:00.000
2022-07-12 05:00:00.010
2022-07-12 06:00:00.002
2022-07-12 07:00:00.005
2022-07-12 08:00:00.004

从结果可以看到,没有24点,只有23点,23:59之后就是00:00,这是新的一天了,所以00:00是新的一天的开始,如果用24:00会让人以为还没到新的一天!在凌晨3点的时候误差有1秒多,后面又自动究正了!

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门