我们之前讨论过时间,在Java 中有一些方法会出现横线?比如Date 过期方法。
新增AI编程课程,引领技术教育新趋势
public static void main(String[] args) throws Exception { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss"); System.out.println(simpleDateFormat.format(new Date())); System.out.println(simpleDateFormat.parse("2018-10-24 12:10:24")); }
附:格式占位符 G 年代标志符 y 年 M 月 d 日 h 时 在上午或下午 (1~12) H 时 在一天中 (0~23) m 分 s 秒 S 毫秒 E 星期 D 一年中的第几天 F 一月中第几个星期几 w 一年中第几个星期 W 一月中第几个星期 a 上午 / 下午 标记符 k 时 在一天中 (1~24) K 时 在上午或下午 (0~11) z 时区复制代码
回到我们遇到的坑:
在SimpleDateFormat源码中,所有的格式化和解析都需要通过一个中间对象Calendar进行转换,而这将会出现线程不安全的操作
比如当多个线程操作同一个Calendar的时候后来的线程会覆盖先来线程的数据,那最后其实返回的是后来线程的数据,这样就导致我们上面所述的BUG的产生
因为SimpleDateFormat线程不安全,很多人都会写个Util类,然后把SimpleDateFormat定义成全局的一个常量,所有线程都共享这个常量:
protected static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd"); public static Date formatDate(String date) throws ParseException { returndayFormat.parse(date); }
对于SimpleDateFormat的解决方法有下面几种:
原因:所有线程都共用一个SimpleDateFormat,
解决办法:每次使用的时候都创建一个新的SimpleDateFormat,我们可以在DateUtils中将创建SimpleDateFormat放在方法内部:
public static Date formatDate(String date) throws ParseException { SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd"); return dayFormat.parse(date); }
上面这个方法虽然能解决我们的问题但是引入了另外一个问题就是,如果这个方法使用量比较大,有可能会频繁造成Young gc,整个系统还是会受一定的影响。
使用ThreadLocal能避免造成Young gc,我们对每个线程都使用ThreadLocal进行保存
由于ThreadLocal是线程之间隔离开的,所以不会出现线程安全问题:
private static ThreadLocal simpleDateFormatThreadLocal = new ThreadLocal<>(); public static Date formatDate(String date) throws ParseException { SimpleDateFormat dayFormat = getSimpleDateFormat(); returndayFormat.parse(date); } private static SimpleDateFormatgetSimpleDateFormat() { SimpleDateFormat simpleDateFormat = simpleDate