如何高效使用SimpleDateFormat

在我们的业务代码中很多地方会用到SimpleDateFormat,把long型的时间转换成string类型,这里就会用到SimpleDateFormat,而这个类不是线程安全的,所以业务代码中往往如下的方式使用:

01 /**
02  * 将毫秒时间转换为 20120813154028 这种形式
03  *
04  * @param millisecond
05  * @return
06  */
07 public static String milliSecondToString(long millisecond) {
08   SimpleDateFormat sd = new SimpleDateFormat("yyyyMMddHHmmss");
09   return sd.format(new Date(millisecond));
10 }

在以前优化hive的udf的时候就发现过这样子使用SimpleDateFormat会很耗时,稍微看下SimpleDateFormat的构造函数就会知道它的构造函数会调用正则,所以应该尽量少new SimpleDateFormat。

​我们来做下测试:

01 import java.text.SimpleDateFormat;
02 import java.util.Date;
03  
04 import org.apache.commons.lang.time.FastDateFormat;
05  
06 public class PerfDateFormat {
07  
08   /**
09    * 将毫秒时间转换为 20120813154028 这种形式
10    *
11    * @param millisecond
12    * @return
13    */
14   public static String milliSecondToString(long millisecond) {
15     SimpleDateFormat sd = new SimpleDateFormat("yyyyMMddHHmmss");
16     return sd.format(new Date(millisecond));
17   }
18  
19   static ThreadLocal<SimpleDateFormat> yyyyMMddHHmmss = new ThreadLocal<SimpleDateFormat>() {
20     @Override
21     protected SimpleDateFormat initialValue()
22     {
23       return new SimpleDateFormat("yyyyMMddHHmmss");
24     }
25   };
26   public static String milliSecondToStringOpt(long millisecond) {
27     return yyyyMMddHHmmss.get().format(new Date(millisecond));
28   }
29  
30   static FastDateFormat yyyyMMddHHmmssF = FastDateFormat
31       .getInstance("yyyyMMddHHmmss");
32  
33   public static String milliSecondToStringUseFastDateFormat(long millisecond) {
34     return yyyyMMddHHmmssF.format(new Date(millisecond));
35   }
36  
37   public static void perf(int count) {
38     System.out.println("Time " + milliSecondToString(new Date().getTime()));
39     long start = System.currentTimeMillis();
40     for (int i = 0; i < count; i++) {
41       long seconds = new Date().getTime();
42       milliSecondToString(seconds);
43     }
44     long end = System.currentTimeMillis();
45     long cost1 = (end - start);
46     System.out.println("c1 " + cost1);
47     System.out.println("Time " + milliSecondToString(new Date().getTime()));
48     start = System.currentTimeMillis();
49     // SimpleDateFormat sd = new SimpleDateFormat("yyyyMMddHHmmss");
50     for (int i = 0; i < count; i++) {
51       long seconds = new Date().getTime();
52       milliSecondToStringOpt(seconds);
53     }
54     end = System.currentTimeMillis();
55     long cost2 = (end - start);
56     System.out.println("c2 " + cost2);
57     System.out.println(cost1 - cost2);
58     System.out.println(cost1 / cost2);
59     System.out.println((double) cost1 / count);
60     start = System.currentTimeMillis();
61     for (int i = 0; i < count; i++) {
62       long seconds = new Date().getTime();
63       milliSecondToStringUseFastDateFormat(seconds);
64     }
65     end = System.currentTimeMillis();
66     long cost3 = (end - start);
67     System.out.println("c3 " + cost3);
68   }
69  
70   public static void main(String[] args) {
71     perf(10000000);
72   }
73 }

milliSecondToString、milliSecondToStringOpt、milliSecondToStringUseFastDateFormat这三个方法都是完成相同的功能,循环调用这个方法1千万次,测试结果如下:

Time 20140305103942

c1 51743
Time 20140305104033
c2 5015
46728
10
0.0051743
c3 11034
 
这个测试结果是在我自己的笔记本上面做的,我们发现采用ThreadLocal的 milliSecondToStringOpt是最快的,其次是 milliSecondToStringUseFastDateFormat采用了 apache的 FastDateFormat,最后面是 milliSecondToString。而 milliSecondToStringOpt是 milliSecondToString的十倍,调用一千万次, milliSecondToString可以节省46s左右,像线上有几十亿条记录,假设每条记录调用 milliSecondToString一次(实际情况是每次会调用多次),以10亿来算,那么就会节省1.277个小时。

猜你喜欢

转载自bupt04406.iteye.com/blog/2028015