"DateFormat 不是同步的。建议为每个线程创建独立的格式实例。如果多个线程同时访问一个格式,则它必须保持外部同步。"----摘自JDK文档中文版
首先让我们看看一个简单的方法
public static Date toDate(String dateStr) {
SimpleDateFormat p= new SimpleDateFormat("yyyyMMdd");
try{
return p.parse(dateStr);
}catch (ParseException e) {
}
return null;
}
这个方法是把形如"20110101"这样的字符串转换成Date类型;同时方法是支持多线程并发访问的,但是这个是有代价的,因为每次方法调用都要创建一个SimpleDateFormat 对象。
很自然的我们就想到以下的改进,将SimpleDateFormat声明为静态全局变量
private static final SimpleDateFormat PATTERN = new SimpleDateFormat("yyyyMMdd");
同时为了保证多线程同步访问,方法需要加锁
public synchronied static Date toDate(String dateStr) {
try{
return PATTERN.parse(dateStr);
}catch (ParseException e) {
}
return null;
}
这样的优化还是不够的,因为在多线程争用的情况下,性能不佳。最好是每个线程都有自己的DateFormat,这样既不会发生争用,而且对于每个线程都只创建一个DateFormat对象。
ThreadLocal正好可以满足这种需求。这里不多做解释了,我们一步到位:
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
public class DateFormatFactory {
private static final Map<String, ThreadLocal<SimpleDateFormat>> pool = new HashMap<String, ThreadLocal<SimpleDateFormat>>();
private static final Object lock = new Object();
public static SimpleDateFormat getDateFormat(String pattern) {
ThreadLocal<SimpleDateFormat> tl = pool.get(pattern);
if (tl == null) {
synchronized (lock) {
tl = pool.get(pattern);
if (tl == null) {
final String p = pattern;
tl = new ThreadLocal<SimpleDateFormat>() {
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat(p);
}
};
pool.put(p, tl);
}
}
}
return tl.get();
}
}
public static Date toDate(String dateStr,String pattern) {
try{
return getDateFormat(pattern).parse(dateStr);
}catch (ParseException e) {
}
return null;
}
上面还增加了对不同Pattern的ThreadLocal的缓存,这样对于每一个线程每一种pattern都只要创建一个SimpleDateFormat对象,多线程访问无需争用。
代码还要很多待改进的地方,如对于非法的pattern不要缓存,是否存在更快、更节约内存的方法。。。。。。
匆匆忙忙,如有错误的地方望不吝赐教!