前言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