多线程下使用 SimpleDateFormat 的问题

最近用到多线程写通信服务,发现在解析时间是一直莫名的错误,最后获取的时间和设备给我传输的时间经常不一致,时间有0144-12-12、2144-02-12等。很莫名其妙!

 

经过分析得出在转换时间时使用了SimpleDateFormat ,SimpleDateFormat是线程不安全的。

 

Tim Cull使用Threadlocal解决了此问题,对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本,代码如下:

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保证是线程安全的,并且更高效。

备注:没有找到相应的prase 方法。 

 

你可能感兴趣的:(多线程下使用 SimpleDateFormat 的问题)