`

安全有效地提升simpleDateFormat性能

 
阅读更多

首先看下JDK原始文档SimpleDateFormat的描述:

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.

因此SimpleDateFormat带来的严重的性能问题,创建一个 SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下。即使将 SimpleDateFormat定义为静态类变量,貌似能解决这个问题,但是SimpleDateFormat是非线程安全的,同样存在问题,如果用 ‘synchronized’线程同步同样面临问题,同步导致性能下降(线程之间序列化的获取SimpleDateFormat实例)。

为什么创建一个simpleDateFormat会花费很大的代价了?

 

note that performance is bad because SimpleDateFormat has a calendar instance as a member and it is allocation of
the calendar object that is expensive. This is also why it isn’t thread safe – if 2 threads change the calendar da te or timezone or something at once the formats returned will be inconsistent.

 

上面的解释在于simpleDateFormat有一个calender的实例变量,分配这个变量的代价是昂贵的。这也是为什么它不是线程安全的原因了,如果2个线程同时修改了这个calendar的时间信息,那么format的输出自然是不正确的。

 

private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);

 

为了解决线程安全问题可以使用ThreadLocal,使用如下:

 

第一种方式:

 

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 使用ThreadLocal以空间换时间解决SimpleDateFormat线程安全问题。
 * 
 * @author
 * 
 */
public class DateUtil {

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    @SuppressWarnings("rawtypes")
    private static ThreadLocal threadLocal = new ThreadLocal() {
        protected synchronized Object initialValue() {
            return new SimpleDateFormat(DATE_FORMAT);
        }
    };

    public static DateFormat getDateFormat() {
        return (DateFormat) threadLocal.get();
    }

    public static Date parse(String textDate) throws ParseException {
        return getDateFormat().parse(textDate);
    }
}

 

创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。

 

第二种方式:

 

import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * 使用ThreadLocal以空间换时间解决SimpleDateFormat线程安全问题。
 * 
 * @author
 * 
 */
public class DateUtil {

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    // 第一次调用get将返回null
    private static ThreadLocal threadLocal = new ThreadLocal();

    // 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
    public static DateFormat getDateFormat() {
        DateFormat df = (DateFormat) threadLocal.get();
        if (df == null) {
            df = new SimpleDateFormat(DATE_FORMAT);
            threadLocal.set(df);
        }
        return df;
    }

}
 

我们看下我们覆盖的initialValue方法:

 

protected T initialValue() {
 return null;//直接返回null
}

 

第三种方式:

   apache commons-lang包的DateFormatUtils或者FastDateFormat实现,apache保证是线程安全的,并且更高效。

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics