Java DateFormat并发实现_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java DateFormat并发实现

Java DateFormat并发实现

 2014/8/19 21:14:20  bert82503  程序员俱乐部  我要评论(0)
  • 摘要:根据javadocs描述,DateFormat类是非线程安全的。通过多线程测试,也证实了这一点。/***可格式化的日期接口定义。**@authorBertLee*@version2014-8-16*/publicinterfaceDateFormattable{/***默认日期格式*/StringPATTERN="yyyy-MM-dd";/***FormatsaDateintoadate/timestring.**@paramdate*@return*@seejava.text
  • 标签:for 实现 Java

class="Apple-converted-space">??? 根据javadocs描述,DateFormat类是非线程安全的。通过多线程测试,也证实了这一点。

/**
 * 可格式化的日期接口定义。
 * 
 * @author  Bert Lee
 * @version 2014-8-16
 */
public interface DateFormattable {

	/**
	 * 默认日期格式
	 */
	String PATTERN = "yyyy-MM-dd";

	/**
	 * Formats a Date into a date/time string.
	 * 
	 * @param date
	 * @return
	 * @see java.text.DateFormat#format(Date)
	 */
	String format(Date date);

	/**
	 * Parses text from the beginning of the given string to produce a date.
	 * 
	 * @param source
	 * @return
	 * @throws ParseException
	 * @see java.text.DateFormat#parse(String)
	 */
	Date parse(String source) throws ParseException;

}

?

/**
 * {@link DateFormat} wrapper.
 *
 * @author	Bert Lee
 * @version 2014-8-16
 */
public class DateFormatWrapper implements DateFormattable {

	private final DateFormat format;

	public DateFormatWrapper() {
		this(PATTERN);
	}

	public DateFormatWrapper(String pattern) {
		this.format = new SimpleDateFormat(pattern);
	}

	/**
	 * <font color="red">经多线程UT验证,format都正确运行!</font>
	 */
	@Override
	public String format(Date date) {
		return this.format.format(date);
	}

	/**
	 * <font color="red">经多线程UT验证,parse经常出问题!</font>
	 */
	@Override
	public Date parse(String source) throws ParseException {
		return this.format.parse(source);
	}

}

?

/**
 * Date parse task.
 *
 * @author	Bert Lee
 * @version 2014-8-16
 */
public class DateParseCallable implements Callable<Date> {

	private DateFormattable formatter;

	private String source;

	public DateParseCallable(DateFormattable formatter, String source) {
		this.formatter = formatter;
		this.source = source;
	}

	@Override
	public Date call() throws Exception {
		return this.formatter.parse(source);
	}

}

?

/**
 * Concurrent thread {@link java.util.concurrent.Executor Executor} wrapper.
 *
 * @author	Bert Lee
 * @version 2014-8-16
 */
public class ConcurrentThreadExecutorWrapper<T> {

	private ExecutorService executor;
	
	private Callable<T> task;

	private List<Future<T>> results;
	
	private TestScale runTimes;
	
	public ConcurrentThreadExecutorWrapper(Callable<T> task) {
		this(task, TestScale.BASIC);
	}
	
	public ConcurrentThreadExecutorWrapper(Callable<T> task, TestScale runTimes) {
		// pool with 5 threads
		this.executor = Executors.newFixedThreadPool(5);
		
		this.task = task;
		this.runTimes = runTimes;
	}
	
	public void run() {
		results = new ArrayList<Future<T>>();
		
		// perform 10 times date conversions
		for (int i = 0; i < runTimes.getValue(); i++) {
			results.add(executor.submit(task));
		}
		executor.shutdown();
	}

	public void printResults() throws Exception {
		this.run();
		
		// look at the results
		for (Future<T> result : results) {
			out.println(result.get());
		}
	}

}

?

/**
 * Test for {@link ConcurrentThreadExecutorWrapper}.
 * <p>
 * 参考并优化实现了<a href="http://stackoverflow.com/questions/4021151/java-dateformat-is-not-threadsafe-what-does-this-leads-to">
 * “Java DateFormat is not thread-safe” what does this leads to?</a>
 *
 * @author	Bert Lee
 * @version 2014-8-16
 */
public class DateFormatExecutorTest {

	// 日期转换格式
	private static final String pattern = "yyyy-MM-dd HH:mm";
	
	/*
	 * 经多线程UT验证,DateFormat的format一直都正确运行,但parse经常出问题!
	 * 即使DateFormat的parse运行正常结束,最终结果也可能不对!
	 * 
	 * DateFormatThreadLocal与DateTimeFormatterWrapper都正确运行。
	 */
	@Test(dataProvider = "parse", groups = "parse")
	public void parse(DateFormattable formatter, String source) throws Exception {
		Callable<Date> task = new DateParseCallable(formatter, source);
		ConcurrentThreadExecutorWrapper<Date> executor = new ConcurrentThreadExecutorWrapper<Date>(task);
		out.println(formatter.getClass().getSimpleName() + " parse result:");
		executor.printResults();
	}
	@DataProvider(name = "parse")
	protected static final Object[][] parseTestData() {
		Object[][] testData = new Object[][] {
//				{ new DateFormatWrapper(pattern), "2014-08-16 08:23:07" }, // 经常报错,即使运行结束,最终结果也可能不对!
				{ new DateFormatThreadLocal(pattern), "2014-08-16 08:23:07" },
				{ new DateTimeFormatterWrapper(pattern), "2014-08-16 08:23" },
		};
		return testData;
	}
	
	@Test(dataProvider = "format", groups = "format")
	public void format(DateFormattable formatter) throws Exception {
		Date date = new Date();
		Callable<String> task = new DateFormatCallable(formatter, date);
		ConcurrentThreadExecutorWrapper<String> executor = new ConcurrentThreadExecutorWrapper<String>(task);
		out.println(formatter.getClass().getSimpleName() + " format result:");
		executor.printResults();
	}
	@DataProvider(name = "format")
	protected static final Object[][] formatTestData() {
		Object[][] testData = new Object[][] {
				{ new DateFormatWrapper(pattern) },
				{ new DateFormatThreadLocal(pattern) },
				{ new DateTimeFormatterWrapper(pattern) },
		};
		return testData;
	}

}

?

???? 为了解决并发问题,参考了StackOverflow上的这篇文章《“Java DateFormat is not thread-safe” what does this leads to?》,在此基础上进行了重构及性能测试。文章提供了两种解决方案:

  1. 基于ThreadLocal实现:使用一个ThreadLocal变量来持有DateFormat对象
  2. 直接使用Joda-Time的DateTimeFormatter

经多线程性能测试,DateTimeFormatter要优于DateFormatThreadLocal。

/**
 * {@link DateFormat} thread-local.
 *
 * @author	Bert Lee
 * @version 2014-8-16
 */
public class DateFormatThreadLocal implements DateFormattable {

	private final ThreadLocal<DateFormat> format;

	public DateFormatThreadLocal() {
		this(PATTERN);
	}

	public DateFormatThreadLocal(final String pattern) {
		this.format = new ThreadLocal<DateFormat>() {
			@Override
			protected DateFormat initialValue() {
				return new SimpleDateFormat(pattern);
			}
		};
	}

	@Override
	public String format(Date date) {
		return this.format.get().format(date);
	}

	@Override
	public Date parse(String source) throws ParseException {
		return this.format.get().parse(source);
	}

}
?
/**
 * {@link DateTimeFormatter} wrapper.
 *
 * @author	Bert Lee
 * @version 2014-8-19
 */
public class DateTimeFormatterWrapper implements DateFormattable {

	private final DateTimeFormatter format;
	
	public DateTimeFormatterWrapper() {
		this(PATTERN);
	}
	
	public DateTimeFormatterWrapper(String pattern) {
		this.format = DateTimeFormat.forPattern(pattern);
	}
	
	@Override
	public String format(Date date) {
		return this.format.print(date.getTime());
	}

	/**
	 * <font color="red">日期字符串表示要与日期模式完全匹配,不然会抛异常!</font>
	 */
	@Override
	public Date parse(String source) throws ParseException {
		DateTime dt = this.format.parseDateTime(source);
		return dt.toDate();
	}

}
?
public class DateFormatExecutorTest {

	// 日期转换格式
	private static final String pattern = "yyyy-MM-dd HH:mm";
	
	/*
	 * 经多线程性能测试,DateTimeFormatter要优于DateFormatThreadLocal。
	 */
	@Test(dataProvider = "profileParse", groups = "profile")
	public void profileParse(DateFormattable formatter, String source) throws Exception {
		String className = formatter.getClass().getSimpleName() + "'s parse";
		RunTimeStats timeStats = new RunTimeStats(className);
		
		Callable<Date> task = new DateParseCallable(formatter, source);
		ConcurrentThreadExecutorWrapper<Date> executor = new ConcurrentThreadExecutorWrapper<Date>(task, TestScale.TINY);
		executor.run();
		
		timeStats.print();
	}
	@DataProvider(name = "profileParse")
	protected static final Object[][] profileParseTestData() {
		Object[][] testData = new Object[][] {
				{ new DateFormatThreadLocal(pattern), "2014-08-16 08:23:07"},
				{ new DateTimeFormatterWrapper(pattern), "2014-08-16 08:23" },
		};
		return testData;
	}
	
	@Test(dataProvider = "profileFormat", groups = "profile")
	public void profileFormat(DateFormattable formatter) throws Exception {
		String className = formatter.getClass().getSimpleName() + "'s format";
		RunTimeStats timeStats = new RunTimeStats(className);
		
		Date date = new Date();
		Callable<String> task = new DateFormatCallable(formatter, date);
		ConcurrentThreadExecutorWrapper<String> executor = new ConcurrentThreadExecutorWrapper<String>(task, TestScale.TINY);
		executor.run();
		
		timeStats.print();
	}
	@DataProvider(name = "profileFormat")
	protected static final Object[][] profileFormatTestData() {
		Object[][] testData = new Object[][] {
				{ new DateFormatThreadLocal(pattern) },
				{ new DateTimeFormatterWrapper(pattern) },
		};
		return testData;
	}

}
?

??? 完整的源码见附件啦~

?

玩得开心!

  • Effective_Java.zip (204.7 KB)
  • 下载次数: 0
  • 相关文章
发表评论
用户名: 匿名