Java DateFormat 병행 실현

13389 단어 자바Date
javadocs 에 따 르 면 DateFormat 。 , 。 
    이번 테스트 를 통 해 얻 은 경험 들:
  • 다 중 스 레 드 병발 UT 검증 을 통 해 DateFormat 의 format 는 올 바 르 게 실행 되 었 으 나 parse 는 자주 문제 가 발생 합 니 다 (어떠한 병발 기술 도 사용 하지 않 음)
  • DateFormat 의 parse 운행 이 정상적으로 끝나 도 최종 결 과 는 틀 릴 수 있 습 니 다!
  • DateFormatterThread Local, DateFormatterWrapper 와 FastDateFormatterWrapper 가 모두 올 바 르 게 실 행 됩 니 다
  • 500 병발 량 + 5 개의 스 레 드 의 성능 테스트 를 통 해 format 작업 에 있어 DateTimeFormatterWrapper 가 가장 좋 고 FastDateFormatterWrapper 가 그 다음 이 며 DateFormatterThread Local 이 가장 나쁘다.parse 조작 에 있어 서 세 사람의 차 이 는 매우 적다
  • .
     
    /**
     *            。
     * 
     * @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     (  StringBuffer  )!</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       (  StringBuffer  ), parse     (         )!
    	 *   DateFormat parse      ,         !
    	 * 
    	 * DateFormatThreadLocal、DateTimeFormatterWrapper FastDateFormatWrapper     。
    	 */
    	@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" },
    				{ new FastDateFormatWrapper(pattern), "2014-08-16 08:23:07" },
    		};
    		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) },
    				{ new FastDateFormatWrapper(pattern) },
    		};
    		return testData;
    	}
    
    }

     
         병발 문 제 를 해결 하기 위해 StackOverflow 의 이 글 인 “Java DateFormat is not thread-safe” what does this leads to?Java Best Practices – DateFormat in a Multithreading Environment 을 참고 하여 이 를 바탕 으로 재 구성 및 성능 테스트 를 실시 했다.글 은 세 가지 해결 방안 을 제공 했다.
  • ThreadLocal : ThreadLocal 변 수 를 바탕 으로 소지 DateFormat 대상
  • 직접 사용 Joda-Time 의 DateTimeFormatter
  • 직접 사용 Apache Commons Lang 3.x 의 FastDateFormat
  •      500 병발 량 + 5 개의 스 레 드 성능 테스트 를 통 해 format 작업 에 있어 DateTimeFormatterWrapper 가 가장 좋 고 FastDateFormatterWrapper 가 그 다음 이 며 DateFormatterThreadLocal 이 가장 나쁘다.parse 작업 에 있어 서 세 사람의 차 이 는 매우 적다.
     
    /**
     * {@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();
    	}
    
    }
     
    /**
     * {@link FastDateFormat} is a fast and thread-safe version of
     * {@link java.text.SimpleDateFormat}.<p>
     * 
     * FastDateFormat implements the behavior of Java 7.
     *
     * @author	Bert Lee
     * @version 2014-8-26
     */
    public class FastDateFormatWrapper implements DateFormattable {
    
    	private final FastDateFormat format;
    	
    	public FastDateFormatWrapper() {
    		this(PATTERN);
    	}
    	
    	public FastDateFormatWrapper(String pattern) {
    		this.format = FastDateFormat.getInstance(pattern);
    	}
    	
    	@Override
    	public String format(Date date) {
    		return this.format.format(date);
    	}
    
    	@Override
    	public Date parse(String source) throws ParseException {
    		return this.format.parse(source);
    	}
    
    }
     
    public class DateFormatExecutorTest {
    
    	//       
    	private static final String pattern = "yyyy-MM-dd HH:mm";
    	
    	/*
    	 *   500   +5          ,
    	 *   format  ,DateTimeFormatterWrapper   ,FastDateFormatWrapper   ,DateFormatThreadLocal   ;
    	 *   parse  ,        。
    	 */
    	@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.SMALL);
    		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" },
    				{ new FastDateFormatWrapper(pattern), "2014-08-16 08:23:07" },
    		};
    		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.MIDDLE);
    		executor.run();
    		
    		timeStats.print();
    	}
    	@DataProvider(name = "profileFormat")
    	protected static final Object[][] profileFormatTestData() {
    		Object[][] testData = new Object[][] {
    				{ new DateFormatThreadLocal(pattern) },
    				{ new DateTimeFormatterWrapper(pattern) },
    				{ new FastDateFormatWrapper(pattern) },
    		};
    		return testData;
    	}
    
    }
     
        온전한 원본 은 첨부 파일 참조 ~
     
     
    즐 거 운 시간 보 내세 요! ^ ^

    좋은 웹페이지 즐겨찾기