SimpleDateFormat与DateTimeFormatter

最近在项目中,涉及到日期转换以及多线程的一些问题。如果不涉及到多线程,则两者都可放心大胆的用。但是涉及到多线程的问题,就得注意下了,SimpleDateFormat是线程不安全。
1.何谓线程不安全?
多线程的执行并不是一个线程一个线程的顺序执行,而是相互抢夺cpu资源,拿到资源的就会执行。正式这个特点,如果这两个线程有一个公共的变量,一个线程读取变量并对变量做修改,那么另外一个线程两次访问的变量就会不同。
2.为什么simpleDateFormat是线程不安全?
我们先得看simpleDateFormat的源码

@Override
    public StringBuffer format(Date date, StringBuffer toAppendTo,
                               FieldPosition pos)
    {
    //  如此轻易地使用内部变量,肯定不能线程安全
    //  线程都对pos进行写操作,必然会影响其他线程的读操作
        pos.beginIndex = pos.endIndex = 0;
        return format(date, toAppendTo, pos.getFieldDelegate());
    }

    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                FieldDelegate delegate) {
        // Convert input date to time field list
       // 这里已经彻底毁坏线程的安全性,这里的calendar变量是继承自父类DateFormat
        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++];
            }

            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;

            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;

            default:
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }

3.解决办法:

  • 加线程同步锁:synchronized(lock),缺点:执行效率低下
  • 将SimpleDateFormat设置成局部变量,缺点:每次调用都会创建对象,结束之后还要清理
  • 使用DateTimeFormatter代替

4.DateTimeFormatter的用法

    /**
     * 从Java 8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:
     * 本地日期和时间:LocalDateTime,LocalDate,LocalTime;
     * 带时区的日期和时间:ZonedDateTime;
     * 时刻:Instant;
     * 时区:ZoneId,ZoneOffset;
     * 时间间隔:Duration。
     * 以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter。
     */
    public static void main(String[] args) {
        // 指定日期和时间:
        LocalDate d2 = LocalDate.of(2019, 11, 30); // 2019-11-30, 注意11=11月
        LocalTime t2 = LocalTime.of(15, 16, 17); // 15:16:17
        LocalDateTime dt2 = LocalDateTime.of(2019, 11, 30, 15, 16, 17);
        LocalDateTime dt3 = LocalDateTime.of(d2, t2);

        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(dtf.format(LocalDateTime.now()));//2020-06-18 00:47:32
        LocalDateTime ldt=LocalDateTime.parse("2019-05-12 12:00:00",dtf);//2019-05-12T12:00
        /**
         * 注意ISO 8601规定的日期和时间分隔符是T。标准格式如下:
         * 日期:yyyy-MM-dd
         * 时间:HH:mm:ss
         * 带毫秒的时间:HH:mm:ss.SSS
         * 日期和时间:yyyy-MM-dd'T'HH:mm:ss
         * 带毫秒的日期和时间:yyyy-MM-dd'T'HH:mm:ss.SSS
         */

        // 本月第一天0:00时刻:
        LocalDateTime firstDay = LocalDate.now().withDayOfMonth(1).atStartOfDay();
        System.out.println(firstDay);

        // 本月最后1天:
        LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        System.out.println(lastDay);

        // 下月第1天:
        LocalDate nextMonthFirstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth());
        System.out.println(nextMonthFirstDay);

        //要判断两个LocalDateTime的先后,可以使用isBefore()、isAfter()方法,对于LocalDate和LocalTime类似
        LocalDateTime target=LocalDateTime.of(2020,6,10,22,10,10);
        System.out.println(LocalDateTime.now().isAfter(target));//true
        System.out.println(LocalDateTime.now().isBefore(target));//false

        /**
         * 注意到LocalDateTime无法与时间戳进行转换,因为LocalDateTime没有时区,无法确定某一时刻。
         * ZonedDateTime相当于LocalDateTime加时区的组合,它具有时区,可以与long表示的时间戳进行转换。
         */
        System.out.println(ZoneId.systemDefault());//Asia/Shanghai
        System.out.println(LocalDateTime.now().atZone(ZoneId.of("America/New_York")));
    }
}

参考自https://www.liaoxuefeng.com/wiki/1252599548343744/1303904694304801

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值