代碼里邊偶然發現一個bug,代碼如下,
public class DateUtil{
// format默認格式
private static String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
protected synchronized DateFormat initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
};
// 根據傳入的format生成對應的SimpleDateFormat
public static SimpleDateFormat getDateFormatInstance(String format) {
if (null != format && !format.equals("")) {
DATE_FORMAT = format;
} else {
DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
}
return (SimpleDateFormat) threadLocal.get();
}
}
這段代碼是用來做日期的format的,考慮到性能問題,這里采用了ThreadLocal來獲取SimpleDateFormat,而不是采用傳統的new方式。在容器加載上述代碼的時候,靜態變量threadLocal 會被初始化,DateFormat的格式為默認,即"yyyy-MM-dd HH:mm:ss",所以如果當我們這樣使用該工具類的時候就出了問題,如下:
DateUtil.getDateFormatInstance("yyyy-MM-dd").format(Calendar.getInstance().getTime());
得到的日期字符串格式不是我們想要的"yyyy-MM-dd"格式,而是"yyyy-MM-dd HH:mm:ss"默認格式。這個不難理解,因為threadLocal 只初始化了一次,并且DateFormat為默認格式。如果想format不同格式的日期,正確的姿勢是這樣的:
public class DateUtil{
private static String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
// 鎖對象
private static final Object lockObj = new Object();
private static Map<String, ThreadLocal<SimpleDateFormat>> threadLocalMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();
public static SimpleDateFormat getDateFormatInstance(final String format) {
ThreadLocal<SimpleDateFormat> tLocal = threadLocalMap.get(format);
if (null == tLocal) {
synchronized (lockObj) {
if (null == tLocal) {
tLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
if (null != format && !format.equals("")) {
DATE_FORMAT = format;
} else {
DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
}
return new SimpleDateFormat(DATE_FORMAT);
};
};
threadLocalMap.put(format, tLocal);
}
}
}
return tLocal.get();
}
}
上邊只是一個ThreadLocal的使用場景和姿勢,那我就在想,ThreadLocal是什么,可以用來做什么?有什么優勢?
有人這樣解釋的,我覺得挺好:
ThreadLocal的作用是提供線程內的局部變量,這種變量在線程的生命周期內起作用,減少同一個線程內多個函數或者組件之間一些公共變量的傳遞的復雜度。具體參考[Java并發包學習七]解密ThreadLocal 這篇文章。