关于jdk1.7的SimpleDateFormat类线程不安全

项目中,经常会用到日期操作。今天在项目中,运行发现多线程调用SimpleDateFormat,抛出异常的情况,而且是选择性的抛出,实际环境很难复现。

     我们模拟以下2种场景:
  
a、单实例场景1

		final DateFormat df = new SimpleDateFormat("yyyyMMdd,HHmmss");
		ExecutorService ts = Executors.newFixedThreadPool(100);
		for (;;) {
			ts.execute(new Runnable() {

				@Override
				public void run() {
					try {
						df.format(new Date(new Random().nextLong()));
					} catch (Exception e) {
						e.printStackTrace();
						System.exit(1);
					}
				}
			});
		}

  

b、多实例场景2

	final ThreadLocal<DateFormat> tl = new ThreadLocal<DateFormat>(){
			@Override
			protected DateFormat initialValue() {
				return new SimpleDateFormat("yyyyMMdd,HHmmss");
			}
			
		};
		ExecutorService ts = Executors.newFixedThreadPool(100);
		for (;;) {
			ts.execute(new Runnable() {

				@Override
				public void run() {
					try {
						tl.get().format(new Date(new Random().nextLong()));
					} catch (Exception e) {
						e.printStackTrace();
						System.exit(1);
					}
				}
			});
		}

 

       运行结果对比可以看到,场景2可以稳定运行,而场景1却频率抛出如下异常:

java.lang.ArrayIndexOutOfBoundsException: 2397709
    at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:454)
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2333)
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2248)
    at java.util.Calendar.setTimeInMillis(Calendar.java:1140)
    at java.util.Calendar.setTime(Calendar.java:1106)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:955)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:948)
    at java.text.DateFormat.format(DateFormat.java:336)
    at foo.Bar$1.run(Bar.java:24)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

      看出 SimpleDateFormat.format并非线程安全的,建议可以采用以下方式解决:

解决方法

a、使用sychronized
b、使用ThreadLocal
c、每次使用new SimpleDateFormat实例
d、也可以使用joda-time等第三方库

posted @ 2013-11-19 18:58  gisorange  阅读(2075)  评论(0编辑  收藏  举报