LocalDateTime

SimpleDateFormat 线程不安全

SimpleDateFormat format方法是线程不安全的,源码如下:

// Called from Format after creating a FieldDelegate
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++];
        }

        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;
}

线程不安全的原因就是calendar这个对象是共享变量,不是栈封闭的状态。所以多线程情况下对calendar的写会造成竞争。解决方案有:

  1. 对写calendar对象加锁,但是开销大。
  2. 每次格式化的时候新创建SimpleDateFormat对象,用起来麻烦。
  3. 使用ThroldLocal,实现起来相对麻烦。
  4. 使用joda工具包,需要引入第三方包
  5. 使用LocalDateTime(推荐)

LocalDate

LocalDate 只包含日期

System.out.println(LocalDate.now());
2021-03-24

LocalTime

LocalTime 只包含时间

System.out.println(LocalTime.now());
16:03:23.272769

LocalDateTime

LocalDateTime就是LocalDate+LocalTime

package com.xiaolyuh;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;

public class LocalDateTimeTest {
    public static void main(String[] args) {
        // 获取当前时间
        System.out.println(LocalDateTime.now());
        // 格式化时间
        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        // 设置时间
        System.out.println(LocalDateTime.now().withYear(2019).withMonth(12));
        // 指定时间初始化
        System.out.println(LocalDateTime.of(2020, 3, 24, 15, 20));
        // 获取年月日
        System.out.println(LocalDateTime.now().getYear());
        System.out.println(LocalDateTime.now().getMonth().getValue());
        System.out.println(LocalDateTime.now().getDayOfMonth());
        System.out.println(LocalDateTime.now().getDayOfWeek().getValue());
        System.out.println(LocalDateTime.now().getDayOfYear());
        System.out.println(LocalDateTime.now().getHour());
        System.out.println(LocalDateTime.now().getMinute());
        System.out.println(LocalDateTime.now().getSecond());

        // 时间计算
        System.out.println(LocalDateTime.now().plusDays(1));
        System.out.println(LocalDateTime.now().minusDays(1));

        // 获取今年第一天 明年第一天
        System.out.println(LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()));
        System.out.println(LocalDateTime.now().with(TemporalAdjusters.firstDayOfNextYear()));

        // 获取今年第一天 0点
        System.out.println(LocalDateTime.of(LocalDate.now(), LocalTime.MIN).with(TemporalAdjusters.firstDayOfYear()));

        // 获取当天0点和24点
        System.out.println(LocalDateTime.of(LocalDate.now(), LocalTime.MIN));
        System.out.println(LocalDateTime.of(LocalDate.now(), LocalTime.MAX));
    }
}

LocalDateTime是通过栈封闭的方式来解决线程安全问题的,具体可以通过如下代码跟一下:

LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))

推荐阅读更多精彩内容