前言

 

啊哈哈,标题写的比较随意了,其实呢最近在各种面试以及博客中,SimpleDateFormat出镜率确实是比较高了,为什么?其实聪明的你们肯定知道,那必须是有坑呗,是的,那我们就以案例来分析一下到底会有那些坑,或者还有没有其他更优的替代方案呢?

正文

 

首先我们来看一下可能会出现在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() 方法的源码一探究竟。

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进行操作的时候,后面的线程有可能会覆盖上一个线程设置好的值,此时就导致前面线程执行的结果被覆盖而返回了一个错误的值。

那我们该如何避免这个坑呢?

 

1、使用ThreadLocal,每个线程中返回各自的实例,避免了多线程环境中共用同一个实例而导致的问题。

 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的使用过程中也是有小坑需要注意的,大家可以参考一下其他的资料,以后可以抽空聊聊这个话题。

2、推荐升级到JDK8+,使用LocalDateTime,LocalDate,LocalTime来代替,具体的用法请自行参考API,当然JDK8所带来的Lambda,Stream等特性也是值得一试的。

3、使用三方包,推荐Joda-Time,对于日期的增减操作也是相当便捷。

github:https://github.com/JodaOrg/joda-time

求求你别用SimpleDateFormat了!的更多相关文章

  1. SimpleDateFormat使用详解——日期、字符串应用

    public class SimpleDateFormat extends DateFormat SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (d ...

  2. SimpleDateFormat转换时间格式

    SimpleDateFormat有两个常用的方法parse和format 其中SimpleDateFormat在创建时有一下集中格式可以选择 SimpleDateFormat sdf = new Si ...

  3. DateUtil(SimpleDateFormat)

    import java.util.Calendar; import java.util.Date; import java.text.SimpleDateFormat; public class Da ...

  4. SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

    java日期格式大全 format SimpleDateFormat(转) SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH ...

  5. java 中的SimpleDateFormat、Date函数以及字符串和Date类型互转

    SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本).解析(文本 -> 日期)和规范化. SimpleDateFor ...

  6. java日期处理SimpleDateFormat等

    1.mysql数据库中有这样一个表: mysql> select * from test_table;+----------+---------------------+| username | ...

  7. SimpleDateFormat的应用

    import java.text.SimpleDateFormat;import java.util.Date;public class Main {    public static void ma ...

  8. 使用 Date 和 SimpleDateFormat 类表示时间、Calendar类和Math类

    一. Date 和 SimpleDateFormat类表示时间 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Date 类.这个类最主要的作用就是获取当 ...

  9. Java SimpleDateFormat使用

    SimpleDateFormat 是一个格式化日期的具体类. 它允许格式化 (date -> text) 和标准化. SimpleDateFormat 允许以为日期-时间格式化选择任何用户指定的 ...

随机推荐

  1. 一步一步理解 python web 框架,才不会从入门到放弃 -- 开始使用 Django

    背景知识 要使用 Django,首先必须先安装 Django. 下图是 Django 官网的版本支持,我们可以看到上面有一个 LTS 存在.什么是 LTS 呢?LTS ,long-term suppo ...

  2. bzoj 4008 亚瑟王 期望概率dp

    对于这种看起来就比较傻逼麻烦的题,最关键的就是想怎么巧妙的设置状态数组,使转移尽可能的简洁. 一开始我想的是f[i][j]表示到第j轮第i张牌还没有被选的概率,后来发现转移起来特别坑爹,还会有重的或漏 ...

  3. BZOJ_3173_[Tjoi2013]最长上升子序列_splay

    BZOJ_3173_[Tjoi2013]最长上升子序列_splay Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数 ...

  4. Spring mvc 上传进度条实现

    以下的仅仅是学习而已,记录以下笔记 1 springmvc 进度条,要实现ProgressListener接口,实现方法update(long readLength, long contextLeng ...

  5. input表单中嵌入百度地图

    在做项目开发中,常常会用到定位的操作,比如在做一些资产房产等方面的业务的时候,需要知道资产的具体位置,并将位置信息保存下来,这个时候我们可以使用form表单嵌入百度地图的方式来实现这个功能,下面请看详 ...

  6. python接口自动化(二十五)--unittest断言——下(详解)

    简介 本篇还是回归到我们最初始的话题,想必大家都忘记了,没关系看这里:传送门  没错最初的话题就是登录,由于博客园的登录机制改变了,本篇以我找到的开源免费的登录API为案例,结合 unittest 框 ...

  7. MyEclipse 10导入JDK1.7或1.8

    1.在MyEclipse,选择“windows”>"preferences"选择,打开“perference”窗口(如下图) 2.展开“perference”窗口左侧“jav ...

  8. 大数据技术之_19_Spark学习_02_Spark Core 应用解析小结

    1.RDD 全称 弹性分布式数据集 Resilient Distributed Dataset它就是一个 class. abstract class RDD[T: ClassTag](    @tra ...

  9. Mybatis增删改查,Demo整合

    第一步:MyBatis的Jar包引入mybatis-3.2.7.jarmysql-connector-java-5.1.8.jar MyBatis的pom.xml依赖 <dependencies ...

  10. MVC页面扩展方法 单例模式

    MVC页面扩展方法    单例模式    /// <summary>         /// 创建一个Config内容对象         /// </summary>     ...