-
SimpleDateFormat对象的parse()方法并不是线程安全的,这是因为该方法内部包含了一些可变状态(例如 SimpleDateFormat 中的 Calendar 对象)。如果多个线程同时调用同一个 SimpleDateFormat 对象的 parse() 方法,就有可能出现以下情况:
-
- 两个或多个线程同时调用 SimpleDateFormat 实例的 parse() 方法。
-
- 因为 SimpleDateFormat 对象中的某些信息是可变的,所以在解析字符串时,所有线程都会对这些信息进行修改。
-
- 由于没有同步控制,所以多个线程之间对这些信息的修改是相互干扰的,导致结果不确定。
-
简单来说,多线程环境下,如果多个线程共用一个 SimpleDateFormat 实例,就会同时对该实例的可变状态进行读写操作,导致线程安全问题。
-
因此,为了避免出现线程安全问题,需要确保每个线程都有自己的SimpleDateFormat 实例,从而避免在解析过程中出现竞态条件。
package com.example.iocdemo.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* threadLocal在解决日期转换并发安全问题
* SimpleDateFormat对象的parse()方法并不是线程安全的,这是因为该方法内部包含了一些可变状态(例如 SimpleDateFormat 中的 Calendar 对象)。如果多个线程同时调用同一个 SimpleDateFormat 对象的 parse() 方法,就有可能出现以下情况:
*
* 1. 两个或多个线程同时调用 SimpleDateFormat 实例的 parse() 方法。
* 2. 因为 SimpleDateFormat 对象中的某些信息是可变的,所以在解析字符串时,所有线程都会对这些信息进行修改。
* 3. 由于没有同步控制,所以多个线程之间对这些信息的修改是相互干扰的,导致结果不确定。
*
* 简单来说,多线程环境下,如果多个线程共用一个 SimpleDateFormat 实例,就会同时对该实例的可变状态进行读写操作,导致线程安全问题。
*
* 因此,为了避免出现线程安全问题,需要确保每个线程都有自己的 SimpleDateFormat 实例,从而避免在解析过程中出现竞态条件。
*/
public class DateUtils {
//直接初始化线程不是安全的
private static SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");
private static final ThreadLocal<DateFormat> df = new ThreadLocal(){
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static String DateToStr(Date date){
return df.get().format(date);
}
public static Date StrToDate(String str) throws ParseException {
return df.get().parse(str);
}
public static void main(String[] args) throws ParseException {
SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
//多个线程调用
Date date = sd.parse("20220311");
System.out.println(date + "threadName" + Thread.currentThread().getName());
} catch (ParseException e) {
System.out.println("============" + e.getMessage());
e.printStackTrace();
}
}).start();
}
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
//线程安全
Date date = StrToDate("20220311");
System.out.println(date + "threadName" + Thread.currentThread().getName());
} catch (ParseException e) {
System.out.println("============" + e.getMessage());
e.printStackTrace();
}
}).start();
}
}
}