Java8 新增 DateTimeFormatter 与 SimpleDateFormat 对比

其实在之前的 Java API 中,日期时间格式化类 SimpleDateFormat 是最常用的工具之一,也是非常让人困惑和提心吊胆的一个,因为经常会听到前辈讲,这个 API 是非线程安全的。

Java8 提供了新的日期时间 API,其中包括用于日期时间格式化的 DateTimeFormatter,它与 SimpleDateFormat 有什么区别呢?

两者最大的区别是,Java8 的 DateTimeFormatter 是线程安全的,而 SimpleDateFormat 并不是线程安全的。

这是不是就意味着,我们在新版本的 JDK 中,要尽量使用线程安全的时间格式化 API DateTimeFormatter 呢?

首先看一下老版本的格式化类是怎么做线程安全处理的。

并发环境下的 SimpleDateFormat

一般来说,为了能够在多线程环境下正确的使用 SimpleDateFormat,最常用的处理方法有这三种:

方法一:局部变量

在需要执行格式化的地方都新建 SimpleDateFormat 实例,使用局部变量来存放 SimpleDateFormat 实例。

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

这种方法的缺点是可能会导致短期内创建大量的 SimpleDateFormat 实例,如解析一个 excel 表格里的字符串日期。

方法二:静态成员变量

为了避免创建大量的 SimpleDateFormat 实例,往往会考虑把 SimpleDateFormat 实例设为静态成员变量,共享 SimpleDateFormat 对象。

这种情况下就要对 SimpleDateFormat 添加同步。

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

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

这种方法的缺点也很明显,就是在高并发的环境下会导致解析被阻塞。

方法三:ThreadLocal(推荐)

要在高并发环境下能有比较好的体验,可以使用 ThreadLocal 来限制 SimpleDateFormat 只能在线程内共享,这样就避免了多线程导致的线程安全问题。

private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
}

public static String format(Date date) {
    return threadLocal.get().format(date);
}

这样就可以保证线程安全性和效率兼顾。

DateTimeFormatter

因为 DateTimeFormatter 类是天然的线程安全,所以可以直接使用,不需要担心线程并发问题。

解析日期:

String dateStr= "2018年08月13日"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");   
LocalDate date= LocalDate.parse(dateStr, formatter);

日期转换为字符串:

LocalDateTime now = LocalDateTime.now();  
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a"); 
String nowStr = now .format(format);

由 DateTimeFormatter 的静态方法 ofPattern() 构建日期格式,LocalDateTime 和 LocalDate 等一些表示日期或时间的类使用 parseformat 方法把日期和字符串做转换。

使用新的 API,整个转换过程都不需要考虑线程安全的问题。

总结

总的来说,新版的 API 简单易用,并且是线程安全的,所以如果用的是 JDK 8 以上的版本,还是首要考虑使用 DateTimeFormatter

至于其他的一些时间 API 使用习惯,也需要改过来,下面会写一篇关于如何互相转换 LocalDateTimeDate 类,这也是阻碍使用 DateTimeFormatter 的一大障碍。

如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论