System.nanoTime()和System.currentTimeMillis()性能问题
Posted cord
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了System.nanoTime()和System.currentTimeMillis()性能问题相关的知识,希望对你有一定的参考价值。
之前给模块做性能优化的时候,需要将性能调到毫秒级,使用了System.nanoTime()和System.currentTimeMillis()对代码分片计时分析耗时操作,后发现在串行情况下性能达到毫秒级,但是一旦在并发压测的时候,性能急剧下降,后经多方排查,发现原因出在System.nanoTime()和System.currentTimeMillis()这两个api上,其在并发情况下耗时会急剧上升,当然在整体上看依然很快,但是在高性能场景下就有很显著的影响。特此记录一下。
测试代码:
1 package cord;
2
3 import java.util.concurrent.CountDownLatch;
4
5 /**
6 * Created by cord on 2018/5/7.
7 */
8 public class SystemApiPerfTest {
9
10 public static void main(String[] args) throws InterruptedException {
11 int count = 100;
12 /**并发*/
13 long interval = concurrentTest(count, ()->{System.nanoTime();});
14 System.out.format("[%s] thread concurrent test <nanoTime> cost total time [%s]ns, average time [%s]ns.
", count, interval, interval/count);
15
16 /**串行循环*/
17 interval = serialNanoTime(count);
18 System.out.format("[%s] count serial test <nanoTime> cost total time [%s]ns, average time [%s]ns.
", count, interval, interval/count);
19
20 System.out.println("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-");
21
22 /**并发*/
23 interval = concurrentTest(count, ()->{System.currentTimeMillis();});
24 System.out.format("[%s] thread concurrent test <currentTimeMillis> cost total time [%s]ns, average time [%s]ns.
", count, interval, interval/count);
25
26 /**串行循环*/
27 interval = serialCurrentTime(count);
28 System.out.format("[%s] count serial test <currentTimeMillis> cost total time [%s]ns, average time [%s]ns.
", count, interval, interval/count);
29
30 }
31
32 private static long concurrentTest(int threads, final Runnable r) throws InterruptedException {
33 final CountDownLatch start = new CountDownLatch(1);
34 final CountDownLatch end = new CountDownLatch(threads);
35
36 for (int i = 0; i < threads; i++) {
37 new Thread(() -> {
38 try {
39 start.await();
40 try {
41 r.run();
42 }finally {
43 end.countDown();
44 }
45 } catch (InterruptedException e) {
46 e.printStackTrace();
47 }
48 }).start();
49 }
50
51 long stime = System.nanoTime();
52 start.countDown();
53 end.await();
54 return System.nanoTime() - stime;
55 }
56
57 private static long serialNanoTime(int count){
58 long stime = System.nanoTime();
59 for (int i = 0; i < count; i++) {
60 System.nanoTime();
61 }
62 return System.nanoTime() - stime;
63 }
64
65 private static long serialCurrentTime(int count){
66 long stime = System.nanoTime();
67 for (int i = 0; i < count; i++) {
68 System.currentTimeMillis();
69 }
70 return System.nanoTime() - stime;
71 }
72 }
测试结果如下:
[100] thread concurrent test <nanoTime> cost total time [5085539]ns, average time [50855]ns.
[100] count serial test <nanoTime> cost total time [2871]ns, average time [28]ns.
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
[100] thread concurrent test <currentTimeMillis> cost total time [7678769]ns, average time [76787]ns.
[100] count serial test <currentTimeMillis> cost total time [4103]ns, average time [41]ns.
串行情况下耗时趋于稳定,但是在并行情况下就不一样了。
因为这两个api都是native方法,涉及到系统层级的调用,与平台有关。
主要原因有两点:
- JVM使用gettimeofday()而不是clock_gettime()来获取时间戳;
- 如果使用HPET时间源,gettimeofday()速度非常慢
除此之外,同样的api,在windows平台的性能比linux上快。
具体原因与实现细节可参阅下面这篇文章(可能需要梯子):
http://pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html
以上是关于System.nanoTime()和System.currentTimeMillis()性能问题的主要内容,如果未能解决你的问题,请参考以下文章
System.currentTimeMillis() 和 System.nanoTime() 哪个更快?别用错了!
System.nanoTime() 的 Java 时代? [复制]
为啥 System.nanoTime() 比 System.currentTimeMillis() 慢(在性能上)?
填坑纪事一次用System.nanoTime()填坑System.currentTimeMills()的实例记录