在我们的业务代码中很多地方会用到SimpleDateFormat,把long型的时间转换成string类型,这里就会用到SimpleDateFormat,而这个类不是线程安全的,所以业务代码中往往如下的方式使用:
07 | public static String milliSecondToString(long millisecond) { |
08 | SimpleDateFormat sd = new SimpleDateFormat( "yyyyMMddHHmmss" ); |
09 | return sd.format( new Date (millisecond)); |
在以前优化hive的udf的时候就发现过这样子使用SimpleDateFormat会很耗时,稍微看下SimpleDateFormat的构造函数就会知道它的构造函数会调用正则,所以应该尽量少new SimpleDateFormat。
我们来做下测试:
01 | import java.text.SimpleDateFormat; |
02 | import java.util. Date ; |
04 | import org.apache.commons.lang.time.FastDateFormat; |
06 | public class PerfDateFormat { |
14 | public static String milliSecondToString(long millisecond) { |
15 | SimpleDateFormat sd = new SimpleDateFormat( "yyyyMMddHHmmss" ); |
16 | return sd.format( new Date (millisecond)); |
19 | static ThreadLocal<SimpleDateFormat> yyyyMMddHHmmss = new ThreadLocal<SimpleDateFormat>() { |
21 | protected SimpleDateFormat initialValue() |
23 | return new SimpleDateFormat( "yyyyMMddHHmmss" ); |
26 | public static String milliSecondToStringOpt(long millisecond) { |
27 | return yyyyMMddHHmmss. get ().format( new Date (millisecond)); |
30 | static FastDateFormat yyyyMMddHHmmssF = FastDateFormat |
31 | .getInstance( "yyyyMMddHHmmss" ); |
33 | public static String milliSecondToStringUseFastDateFormat(long millisecond) { |
34 | return yyyyMMddHHmmssF.format( new Date (millisecond)); |
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); |
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(); |
50 | for ( int i = 0 ; i < count; i++) { |
51 | long seconds = new Date ().getTime(); |
52 | milliSecondToStringOpt(seconds); |
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); |
65 | end = System.currentTimeMillis(); |
66 | long cost3 = (end - start); |
67 | System.out.println( "c3 " + cost3); |
70 | public static void main( String [] args) { |
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个小时。