Java時間格式Date和String互相轉換

一 經常使用方案:SimpleDateFormat

public class TimeUtils {
    public static String formatDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static Date parse(String strDate) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return sdf.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

二 出現的問題

每次調用方都要new SimpleDateFormat(),每次處理一個時間信息的時候,就須要建立一個SimpleDateFormat實例對象,而後再丟棄這個對象。大量的對象就這樣被建立出來,佔用大量的內存和 jvm空間安全

因而 那我就建立一個靜態的simpleDateFormat實例多線程

public class TimeUtils {
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static String formatDate(Date date) {
        return sdf.format(date);
    }

    public static Date parse(String strDate) {
        try {
            return sdf.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

可是問題是:線程不安全,在format方法裏,有這樣一段代碼:app

private StringBuffer format(Date date, StringBuffer toAppendTo,
                            FieldDelegate delegate) {
    calendar.setTime(date);
    boolean useDateFormatSymbols = useDateFormatSymbols();
    for (int i = 0; i < compiledPattern.length; ) {
        int tag = compiledPattern[i] >>> 8;
        int count = compiledPattern[i++] & 0xff;
        if (count == 255) {
            count = compiledPattern[i++] << 16;
            count |= compiledPattern[i++];
        }
        switch (tag) {
        case TAG_QUOTE_ASCII_CHAR:
            toAppendTo.append((char)count);
            break;
        case TAG_QUOTE_CHARS:
            toAppendTo.append(compiledPattern, i, count);
            i += count;
            break;
        default:
            subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
            break;
        }
    }
    return toAppendTo;
}
calendar不是方法局部變量而是SimpleDateFormat類的全局變量,而這就是引起問題的根源。想象一下,在一個多線程環境下,有兩個線程持有了同一個SimpleDateFormat的實例,分別調用format方法:
  線程1調用format方法,改變了calendar這個字段。
  中斷來了。
  線程2開始執行,它也改變了calendar。
  又中斷了。
  線程1回來了,此時,calendar已然不是它所設的值,而是走上了線程2設計的道路。若是多個線程同時爭搶calendar對象,則會出現各類問題,時間不對,線程掛死等等。
  分析一下format的實現,咱們不難發現,用到成員變量calendar,惟一的好處,就是在調用subFormat時,少了一個參數,卻帶來了這許多的問題。其實,只要在這裏用一個局部變量,一路傳遞下去,全部問題都將迎刃而解。

三 解決辦法:

1  SimpleDateFormat做爲線程局部變量來使用。2使用對象鎖,代碼以下。3使用jodaTime(推薦)jvm

public class TimeUtils {
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static String formatDate(Date date) {
     	 synchronized(sdf){
         return sdf.format(date);
       }
   }
    public static Date parse(String strDate) {
 		synchronized(sdf){
         try {
             return sdf.parse(strDate);
         } catch (ParseException e) {
             e.printStackTrace();
         }
         return null;
		}
    }

四 jodaTime使用:

public class TimeUtils {
    public static String formatDate(Date date) {
        DateTime dateTime = new DateTime(date);
        String formatStr = "yyyy-MM-dd HH:mm:ss";
        return dateTime.toString(formatStr);
    }
    public static Date parse(String strDate) {
        DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        DateTime dateTime = DateTime.parse(strDate, dateTimeFormat);
        dateTime = dateTime.plusDays(1);
        return dateTime.toDate();
    }
}
相關文章
相關標籤/搜索