【Java】使用DateTimeFormatter替换线程不安全的SimpleDateFormat

如何让SimpleDateFormat保持安全运行?

方案一 每次都去new##

这种方案最简单,但是会导致开销比较大,不推荐

方案二 使用ThreadLocal保障每个线程都有一个SimpleDateFormat##

这个方法是我在这里看到的:https://www.jianshu.com/p/d9977a048dab
我摘一下主要内容:

public class TestSimpleDateFormat2 {
    // (1)创建threadlocal实例
    static ThreadLocal safeSdf = new ThreadLocal(){
        @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.hutoolcommon-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那样存储为全局变量,这样就避免了共享问题,即达到了线程安全的目的,这样就可以使用单例去格式化时间了

你可能感兴趣的:(java)