在我们的业务代码中很多地方会用到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个小时。