關於jdk1.7的SimpleDateFormat類線程不安全

項目中,常常會用到日期操做。今天在項目中,運行發現多線程調用SimpleDateFormat,拋出異常的狀況,並且是選擇性的拋出,實際環境很難復現。java

     咱們模擬如下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卻頻率拋出以下異常:dom

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並不是線程安全的,建議能夠採用如下方式解決:ide

解決方法spa

a、使用sychronized
b、使用ThreadLocal
c、每次使用new SimpleDateFormat實例
d、也能夠使用joda-time等第三方庫線程

相關文章
相關標籤/搜索