如何让SimpleDateFormat保持安全运行?
方案一 每次都去new##
这种方案最简单,但是会导致开销比较大,不推荐
方案二 使用ThreadLocal保障每个线程都有一个SimpleDateFormat##
这个方法是我在这里看到的:https://www.jianshu.com/p/d9977a048dab
我摘一下主要内容:
public class TestSimpleDateFormat2 {
// (1)创建threadlocal实例
static ThreadLocal<DateFormat> safeSdf = new ThreadLocal<DateFormat>(){
@Override
protected SimpleDateFormat initialValue(){
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static void main(String[] args) {
// (2)创建多个线程,并启动
for (int i = 0; i < 10; ++i) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {// (3)使用单例日期实例解析文本
System.out.println(safeSdf.get().parse("2017-12-13 15:17:27"));
} catch (ParseException e) {
e.printStackTrace();
}
}
});
thread.start();// (4)启动线程
}
}
}
方案三 使用第三方包
这个我有尝试cn.hutool
和common-lang3
提供的FastDateFormat
最后的结果其实并不满意,因为这两个包都没能帮助我检查非正常时间,比如2018-07-32这种日期也被认为是正确的时期格式了
方案四 使用JDK8提供的DateTimeFormatter
这个方案就比较完美了,该有的都有了。
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
其实SimpleDateFormat本身就不太好,比如你希望格式为yyyy-MM-dd,然后你传的时间戳是2018-08-08 18:18:18,格式化的时候并不会抛出异常,而是默认给你格式化为yyyy-MM-dd,如果你打算用SimpleDateFormat来做时间格式校验就比较麻烦,所以我更喜欢DateTimeFormatter这种处理方法
2020年8月12日更新
最近研究了一下Java8中这个DateTimeFormatter
的源码,终于知道了,原来线程安全的原因,是因为它把真正去格式化的对象TemporalAccessor
的实现类,通过参数传入,而不是像原来jdk7那样存储为全局变量,这样就避免了共享问题,即达到了线程安全的目的,这样就可以使用单例去格式化时间了