论坛首页 Java企业应用论坛

Java系统时钟几个值得思考的问题

浏览 5989 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-04-10  

System.currentTimeMillis()是依赖于系统时钟的,也就是说,如果你把自己的系统时钟更改了,这个函数的返回会立即生效,变成更改后的值;

System.nanoTime()主要用于记录一个时间段的长度,或者说一个超时,在这个过程中,你更改系统时钟也不会影响。

两个方法的精度一个是毫秒,一个是纳秒,但都是不靠普的(有些系统的时间粒度是10ms),nanoTime()的调用也会消耗几微妙,所以不靠普;

但粒度不是我讨论的重点。

 

我们程序中的timer是很常用的功能,归根到底到下面的API:

 

LockSupport. public static void parkNanos(long nanos) 

 和

 

 

Thread.sleep(long millis)

 

 

不幸的是,但它们都是基于系统时钟的。

下面是我的测试:

	public static void main(String[] args) throws InterruptedException {
		long s = System.nanoTime();
		int _10sec = 10 * 1000;
		LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(_10sec));
		long e = System.nanoTime();
		long used = e - s;
		System.out.println("Used:" + TimeUnit.NANOSECONDS.toMillis(used));
	}

 在运行上面程序之后,在系统命令行执行下面命令重置时间:

[atlas@atlas-pc ~]$ date && sudo date -s 16:10:40
2013年 04月 10日 星期三 16:10:57 CST
2013年 04月 10日 星期三 16:10:40 CST

 java程序输出:Used:27889

我把时钟向前拨了17s,一个park10s的程序27秒后才结束;

同样的,测试Thread:

	public static void main(String[] args) throws InterruptedException {
		long s = System.nanoTime();
		int _10sec = 10 * 1000;
		Thread.sleep(_10sec);
		long e = System.nanoTime();
		long used = e - s;
		System.out.println("Used:" + TimeUnit.NANOSECONDS.toMillis(used));
	}

 运行后,重置时钟:

[atlas@atlas-pc ~]$ date && sudo date -s 16:33:40
2013年 04月 10日 星期三 16:34:03 CST
2013年 04月 10日 星期三 16:33:40 CST

 

java程序输出:Used:33569

 

这篇文章介绍了系统时钟和Java里面的几个API。

 

结论:

当我们重置服务器的时间,

1,那些依赖系统时钟的程序(timer,scheduler,etc)会出现问题,

2,依赖时间判断的心跳会出问题,

 

目前还没有解放方法。

 

 

   发表时间:2013-04-11  
所以说在准备服务器时,都要校时,机器很多时,需要一台时间服务器
0 请登录后投票
   发表时间:2013-04-11  
如果只有单台服务器的话,那没什么好说的,让服务器主板的电池保持有电,不要人为去修改系统时间就行了。如果系统是分布式的,就需要一个对时,现在很多工业上的对时,都是通过一个GPS和卫星对时!
0 请登录后投票
   发表时间:2013-04-12  
是的,需要同步time
0 请登录后投票
   发表时间:2013-05-12  
现在都不怎么用Timer了,一般用ThreadPoolExecutor
0 请登录后投票
   发表时间:2013-05-13  
joelxy 写道
现在都不怎么用Timer了,一般用ThreadPoolExecutor

你说的对,但ThreadPoolExecutor也是无法逃避这个问题的。
0 请登录后投票
   发表时间:2013-05-14  
OpenMind 写道
joelxy 写道
现在都不怎么用Timer了,一般用ThreadPoolExecutor

你说的对,但ThreadPoolExecutor也是无法逃避这个问题的。

ThreadPoolExecutor用的相对时间,非绝对时间,即使改了时钟,线程调度也没有影响
当然,既然用的是相对时间,这样就不能用ThreadPoolExecutor来解决固定时间的调度,比如晚上12点调度某个任务,那个就要用Timer或其它调度器了
如果真要用Timer,解决时钟同步,直接用ntp服务,做过测试,ntp服务貌似会有5分钟左右的时延,但目前也没有需要多么精准的调任务度,还是可以接受
0 请登录后投票
   发表时间:2013-05-14  
joelxy 写道
OpenMind 写道
joelxy 写道
现在都不怎么用Timer了,一般用ThreadPoolExecutor

你说的对,但ThreadPoolExecutor也是无法逃避这个问题的。

ThreadPoolExecutor用的相对时间,非绝对时间,即使改了时钟,线程调度也没有影响
当然,既然用的是相对时间,这样就不能用ThreadPoolExecutor来解决固定时间的调度,比如晚上12点调度某个任务,那个就要用Timer或其它调度器了
如果真要用Timer,解决时钟同步,直接用ntp服务,做过测试,ntp服务貌似会有5分钟左右的时延,但目前也没有需要多么精准的调任务度,还是可以接受


你错了,ThreadPoolExecutor的调度,最终调用的也是LockSupport.park方法,也就是我上面所说的第一种情况。
0 请登录后投票
   发表时间:2013-07-10  
OpenMind 写道
joelxy 写道
OpenMind 写道
joelxy 写道
现在都不怎么用Timer了,一般用ThreadPoolExecutor

你说的对,但ThreadPoolExecutor也是无法逃避这个问题的。

ThreadPoolExecutor用的相对时间,非绝对时间,即使改了时钟,线程调度也没有影响
当然,既然用的是相对时间,这样就不能用ThreadPoolExecutor来解决固定时间的调度,比如晚上12点调度某个任务,那个就要用Timer或其它调度器了
如果真要用Timer,解决时钟同步,直接用ntp服务,做过测试,ntp服务貌似会有5分钟左右的时延,但目前也没有需要多么精准的调任务度,还是可以接受


你错了,ThreadPoolExecutor的调度,最终调用的也是LockSupport.park方法,也就是我上面所说的第一种情况。

可以测试一下
在windows上,修改了时钟,线程调度没有受影响
在linux上,确实受了影响
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics