让DateFormat多线程安全

"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不要缓存,是否存在更快、更节约内存的方法。。。。。。 
匆匆忙忙,如有错误的地方望不吝赐教!

你可能感兴趣的:(java,多线程)