众所周知,SimpleDateFormat是多线程不安全的

下面这段代码通过多线程使用同一个SimpleDateFormat对象的parse方法, 多次执行代码来测试,可以看到会出现两种预想不到的现象----->要么出现不正确的时间解析结果,要么抛出message各异的NumberFormatException异常。 @see>>借助SimpleDateFormat来谈谈java里的多线程不安全

package jstudy.dateformat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleDateFormatTest {
    public static void main(String[] args) throws ParseException, InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(20);
        SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startDate = "2022-01-07 15:40:15";
        for (int i = 0; i < 20; i++) {
            threadPool.execute(() -> {
                for (int j = 0; j < 20; j++) {
                    try {
                        // new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startDate); //使用局部变量可以避免出现线程不安全
                        System.out.println(datetimeFormat.parse(startDate));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

SimpleDateFormat不光线程不安全,还有这个隐患

如下代码运行结果是什么?

    @Test
    public void test() throws ParseException {
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyyMMddHHmmss");//pattern
        System.out.println( simpleDateFormat.parse("2022-09-30 13:53:14"));
    }

答案:

Wed Dec 08 21:00:13 CST 2021

可见,字符串时间与指定的pattern不匹配,导致出现意外结果。

而我们这次在现网排查问题时,正好是遇到了这个坑。

数据库里的付款记录,竟然存在完成时间比创建时间还早的记录,并且还早了多半年。

避坑!SimpleDateFormat不光线程不安全,还有这个隐患

排查原因着实费了几番周折。原来,在三方付款服务商通道对接程序里,在解析付款完成时间时,由于程序员当时的粗心,直接拷贝别的对接程序里的代码,再加上测试没有覆盖到这个case,导致运行了一个月,才发现这个问题。

赶紧加上个必要的代码注释,给“伸手党”式的粗心同学提个醒。

避坑!SimpleDateFormat不光线程不安全,还有这个隐患