共享SimpleDateFormat的并发问题

1、问题提出

梳理订单逻辑时发现对日期格式进行format的代码有如下写法
在这里插入图片描述

在这里插入图片描述

OneDateUtil中定义了一个全局static的SimpleDateFormat对象。SimpleDateFormat对象不是线程安全的,在多线程环境下容易造成数据转换和处理错误

2、为什么SimpleDateFormat线程不安全

SimpleDateFormat在类的注释中标明了并不适合多线程场景
在这里插入图片描述
深入排查,会发现SimpleDateFormat中的format方法中,会将输入的日期给calendar赋值,由于SimpleDateFormat被定义为static类型的,可以被多个线程访问到。当a线程执行了calendar.setTime(date)后,b线程又执行了calendar.setTime(date),此时a线程未执行结束,a线程中的calendar就会被覆盖
在这里插入图片描述
在这里插入图片描述
SimpleDateFormat的parse方法有同样的问题,多线程下执行cal.clear()会出现线程安全问题
在这里插入图片描述
在这里插入图片描述

3、如何修改

方案1:加锁 synchronized修饰,影响性能,禁止。

方案2:局部变量方式,项目中也存在该使用方式,高并发下会创建大量的SimpleDateFormat类对象,不推荐。
在这里插入图片描述
方案3:java 8 中引入新的日期类 API,这些类是不可变的,且线程安全的,推荐。

private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

public static String formatDate(Date date) {
    
    
	LocalDateTime time = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
	return formatter.format(time);
}

DateTimeFormatter的format方式是将入参对象封装在一个新建的DateTimePrintContext对象中,作为入参传给printerParser对象,以局部变量的方式传入到方法中,而不是像SimpleDateFormat那样把日期对象设置到全局变量calendar中进行处理,从而避免了线程安全的问题
在这里插入图片描述

4、风险点

1、前端传的日期非正规日期格式
在这里插入图片描述
2、序列化问题

需要进行序列化的地方,可能存在问题,可以通过加注解解决

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime localDateTime ;



@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate localDate;

猜你喜欢

转载自blog.csdn.net/LXYDSF/article/details/128361166