10

SimpleDateFormat的线程安全问题

 3 years ago
source link: http://www.lzhpo.com/article/166
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

SimpleDateFormat的线程安全问题

// 如果没有加锁,没有去保证线程安全的话,那这个就是错误的写法,是线程不安全的private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

错误示例:

package com.lzhpo.common.config;import org.junit.jupiter.api.Test;import java.text.ParseException;import java.text.SimpleDateFormat;/** * @author Zhaopo Liu */class DateFormatConfigTest {    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    /**     * SimpleDateFormat线程不安全,没有保证线程安全的情况下,禁止使用全局SimpleDateFormat     * <pre>     *     private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     * </pre>     */    @Test    void testParse() {        for (int i = 0; i < 20; ++i) {            Thread thread = new Thread(() -> {                try {                    // 错误                    System.out.println(SIMPLE_DATE_FORMAT.parse("2020-06-01 11:35:00"));                    // 正确//                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-06-01 11:35:00"));                } catch (ParseException e) {                    e.printStackTrace();                }            });            thread.start();        }    }}

从代码中可以看到:SimpleDateFormat继承DateFormat类,在SimpleDateFormat转换日期是通过Calendar对象来操作的,DateFormat类中维护一个Calendar对象,Calendar对象会被用来进行日期-时间计算,既被用于format方法也被用于parse方法。

那就追一下calendar对象:

来到了CalendarBuilderestablish方法:

看一下clear方法,可以发现它并不是线程安全的,如果此时,a线程将calendar清空了,calendar就没有新值了,恰好此时b线程刚好进入到parse方法用到了calendar对象,那就会产生线程安全问题了!

  1. 不使用静态变量SimpleDateFormat,使用局部变量SimpleDateFormat,每次都new一个。

  2. synchronized等等...保证线程安全的情况下使用静态变量SimpleDateFormat

  3. 使用ThreadLocal.withInitial

    /** * 创建线程局部变量SimpleDateFormat */ private static final ThreadLocal<DateFormat> SAFE_FORMAT =    ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));@Testvoid testSafe() {    for (int i = 0; i < 20; ++i) {        Thread thread = new Thread(() -> {            try {                System.out.println(SAFE_FORMAT.get().parse("2020-06-01 11:35:00"));            } catch (ParseException e) {                e.printStackTrace();            }        });        thread.start();    }}
正文到此结束
所属分类:Java开发

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK