关于SimpleDateFormat的一些使用及性能数据
下午在代码review时,和Y同学讨论了SimpleDateFormat的使用,发现自己以前使用有不当的地方,特此记录。
在jdk的doc中指出SimpleDateFormat
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
之前使用的时候,直接new一个,没有考虑到多线程问题,在并发的情况下会有问题。
public static DateFormat dataTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
考虑到该方法在工程中用的比较多,测试了几种常用方法的性能,
测试场景:单线程多次format
, 数据如下:
次数:10w
jdkSimpleDataFormat cost time: 1115ms
apacheSimpleDataFormat cost time: 275ms
threadLocalSimpleDataFormat cost time: 183ms
次数:100w
jdkSimpleDataFormat cost time: 4737ms
apacheSimpleDataFormat cost time: 1572ms
threadLocalSimpleDataFormat cost time: 853ms
次数:1000w
jdkSimpleDataFormat cost time: 35170ms
apacheSimpleDataFormat cost time: 14078ms
threadLocalSimpleDataFormat cost time: 8509ms
从数据可以看出
(1) apache common-lang提供的DateFormatUtils.format方法比JDK提供的SimpleDataFormat.format性能高出
149.82%
(2) ThreadLocal方式比 DateFormatUtils.format 方式性能高出 65.44%
结论:在使用SimpleDataFormat时,尽量使用ThreadLocal 方式。
(2) ThreadLocal方式比 DateFormatUtils.format 方式性能高出 65.44%
结论:在使用SimpleDataFormat时,尽量使用ThreadLocal 方式。
测试代码如下,有兴趣的同学可以测下多线程情形下的性能数据。
package com.bc.perf; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.apache.commons.lang.time.DateFormatUtils; public class SimpleDataFormatPerfTest { private static final int circleNum = 10000000; private static String pattern = "yyyy-MM-dd HH:mm:ss"; private Executor testExecutor = Executors.newFixedThreadPool(64); private static ThreadLocal<SimpleDateFormat> simpleDateFormatProvider = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static void main(String[] args){ SimpleDataFormatPerfTest test = new SimpleDataFormatPerfTest(); SimpleDateFormat format = new SimpleDateFormat(pattern); System.out.println("jdkSimpleDataFormat date format: " + format.format(new Date())); System.out.println("apacheSimpleDataFormat date format: " + DateFormatUtils.format(new Date(), pattern)); System.out.println("threadLocalSimpleDataFormat date format: " + simpleDateFormatProvider.get().format(new Date())); //1 Jdk SimpleDateFormat test.jdkSimpleDataFormatPerf(); //2 Apache common-lang SimpleDateFormat test.apacheSimpleDataFormatPerf(); //3 ThreadLocal SimpleDateFormat test.threadLocalSimpleDataFormatPerf(); } public void jdkSimpleDataFormatPerf() { long t1 = System.currentTimeMillis(); for (int i = 0; i < circleNum; i++) { SimpleDateFormat format = new SimpleDateFormat(pattern); format.format(new Date()); } long t2 = System.currentTimeMillis(); System.out.println("originSimpleDataFormat cost time: " + (t2 - t1)); } public void apacheSimpleDataFormatPerf() { long t1 = System.currentTimeMillis(); for (int i = 0; i < circleNum; i++) { DateFormatUtils.format(new Date(), pattern); } long t2 = System.currentTimeMillis(); System.out.println("apacheSimpleDataFormat cost time: " + (t2 - t1)); } public void threadLocalSimpleDataFormatPerf() { long t1 = System.currentTimeMillis(); for (int i = 0; i < circleNum; i++) { simpleDateFormatProvider.get().format(new Date()); } long t2 = System.currentTimeMillis(); System.out.println("threadLocalSimpleDataFormat cost time: " + (t2 - t1)); } }