前言git
啊哈哈,標題寫的比較隨意了,其實呢最近在各類面試以及博客中,SimpleDateFormat出鏡率確實是比較高了,爲何?其實聰明的大家確定知道,那必須是有坑唄,是的,那咱們就以案例來分析一下到底會有那些坑,或者還有沒有其餘更優的替代方案呢?github
正文面試
首先咱們來看一下可能會出如今DateUtils中的寫法:多線程
private static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static Date formatDate(String date) throws ParseException { return dayFormat.parse(date); }
當咱們在單線程的程序中調用 formatDate(date) ,此時並不會出現任何問題(若是這也出問題那還玩什麼...) ,然而當咱們的程序在多線程併發執行調用這個方法的時候。併發
ExecuterService es = ExecuterService.newFixedThreadPool(50); for( ... ){ es.execute( () -> { System.out.println(parse("2018-11-11 10:35:20")); }) }
此時你會發現打印出來的時間有些是錯誤,程序甚至會拋出異常NumberFormatException??爲何會出現這種狀況呢?咱們能夠直接查看SimpleDateFormat.parse() 方法的源碼一探究竟。spa
private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list 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++\]; }
從源碼能夠看到,在多線程的環境中,執行到第五行 calendar進行操做的時候,後面的線程有可能會覆蓋上一個線程設置好的值,此時就致使前面線程執行的結果被覆蓋而返回了一個錯誤的值。線程
那咱們該如何避免這個坑呢?code
一、使用ThreadLocal,每一個線程中返回各自的實例,避免了多線程環境中共用同一個實例而致使的問題。orm
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<>(); public static Date formatDate(String date) throws ParseException { SimpleDateFormat dayFormat = getSimpleDateFormat(); return dayFormat.parse(date); } private static SimpleDateFormat getSimpleDateFormat() { SimpleDateFormat simpleDateFormat = simpleDateFormatThreadLocal.get(); if (simpleDateFormat == null){ simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); simpleDateFormatThreadLocal.set(simpleDateFormat); } return simpleDateFormat; }
須要注意一點的是,ThreadLocal的使用過程當中也是有小坑須要注意的,你們能夠參考一下其餘的資料,之後能夠抽空聊聊這個話題。
二、推薦升級到JDK8+,使用LocalDateTime,LocalDate,LocalTime來代替,具體的用法請自行參考API,固然JDK8所帶來的Lambda,Stream等特性也是值得一試的。blog
三、使用三方包,推薦Joda-Time,對於日期的增減操做也是至關便捷。
github:https://github.com/JodaOrg/joda-time