日期时间处理问题
yuankaiqiang Lv5

SimpleDateFormat与DateTimeFormatter线程安全问题,参考阿里巴巴Java开发手册规范处理


阿里巴巴开发手册中这样说的

20210716092541

  • 不合规的代码示例:

    1
    2
    3
    4
    public class MyClass {
    private static SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");
    private static Calendar calendar = Calendar.getInstance();
    }
  • 合规的代码实例:

    1
    2
    3
    4
    public class MyClass {
    private SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");
    private Calendar calendar = Calendar.getInstance();
    }

在多线程环境下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MainClass {

private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public static String formatDate(Date date) {
return sdf.format(date);
}

public static Date parse(String strDate) throws ParseException {
return sdf.parse(strDate);
}

public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(100);
for (int i = 0; i < 20; i++) {
service.execute(() -> {
try {
System.out.println(parse("2019-04-03 17:45:00"));
} catch (ParseException e) {
e.printStackTrace();
}

});
}
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);

}
}

输出情况:部分线程获取失败

image-20210716093350061

原因:把SimpleDateFormat定义为静态变量,多线程环境下SimpleDateFormat的实例就会被多个线程共享,B线程会读取到A线程的时间,就会出现时间差异和其他各种问题

SimpleDateFormat和它继承的DateFormat都不是线程安全的

解决

使用JDK1.8的DateTimeFormatter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MainClass {

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

public static String formatDate(LocalDateTime date) {
return formatter.format(date);
}

public static LocalDateTime parse(String dateNow) throws ParseException {
return LocalDateTime.parse(dateNow, formatter);
}

public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(100);
for (int i = 0; i < 20; i++) {
service.execute(() -> {
try {
System.out.println(parse(formatDate(LocalDateTime.now())));
} catch (ParseException e) {
e.printStackTrace();
}

});
}
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
}
}

image-20210716094333455

因此进制在多线程的情况下使用SimpleDateFormat,多线程情况应该使用DateTimeFormatter

阿里JAVA开发手册地址

手册阿里云盘链接:https://www.aliyundrive.com/s/MEtW4t5DdGh

 评论