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

众所周知,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不光线程不安全,还有这个隐患

我们可以确定的是create_time赋值是没问题的。那看来就是payment_finish_time的赋值有问题。

赶紧扒代码,在三方付款服务商的service里,发现如下语句:

//完成时间
payResultVo.setOrderFinishTime(DateUtils.str2Date(qi.getEndTime(),DateUtils.datetimeFormat));

其中,DateUtils 存在于公司公共技术common包,封装了时间相关处理操作,DateUtils#str2Date 是将特定格式的时间字符串转换成Date对象。DateUtils.datetimeFormat 是 public static final SimpleDateFormat datetimeFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

瞬间想到,必然是SimpleDateFormat线程不安全导致的。为了快速解决问题,修改DateUtils#str2Date 的实现:

1 public static Date str2Date(String str, SimpleDateFormat sdf) {
 2     if (null == str || "".equals(str)) {
 3         return null;
 4     }
 5     try {
 6         return sdf.parse(str);
 7     } catch (ParseException e) {
 8         e.printStackTrace();
 9     }
10     return null;
11 }

1 public static Date str2Date(String str, SimpleDateFormat sdf) {
 2     if (null == str || "".equals(str)) {
 3         return null;
 4     }
 5     try {
 6         SimpleDateFormat actualSdf = new SimpleDateFormat(sdf.toPattern());
 7         return actualSdf.parse(str);
 8     } catch (ParseException e) {
 9         e.printStackTrace();
10     }
11     return null;
12 }

后来竟然发现这个改动没起作用!就是说,依然存在付款完成时间早于创建时间的付款单。这就不科学了~

排查原因着实费了几番周折。

再后来,才真相大白。原来,服务商响应报文里的时间格式不是 yyyy-MM-dd HH:mm:ss,而是 yyyyMMddHHmmss 。由于程序员当时的粗心,直接拷贝别的对接程序里的代码,再加上测试没有覆盖到这个case,导致运行了一个月,才发现这个问题。

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

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

Original: https://www.cnblogs.com/buguge/p/16744992.html
Author: buguge
Title: 避坑!SimpleDateFormat不光线程不安全,还有这个隐患

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/591604/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 边缘计算 | 在移动设备上部署深度学习模型的思路与注意点 ⛵

    💡 作者:韩信子@ShowMeAI📘 深度学习◉技能提升系列:https://www.showmeai.tech/tutorials/35📘 深度学习实战系列:https://ww…

    数据库 2023年6月14日
    0104
  • Docker 从入门到入土

    1、Docker简介 1.1 虚拟化技术 介绍 Docker之前有必要了解一下虚拟化技术,其实Docker的出现也是虚拟机技术发展的一个里程碑。随着企业业务量的不断提升,需要横向的…

    数据库 2023年6月6日
    083
  • JUC学习笔记(三)

    线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。我们来基本一道面试常见的题目来分析 JUC学习笔记(一)https://www.cnblogs.co…

    数据库 2023年6月6日
    089
  • Host-Only模式下虚拟机无法联网问题

    环境: 镜像:Linux CentOS7——————————…

    数据库 2023年6月11日
    092
  • HTML&CSS-盒模型运用居中方式合集

    { margin: 0; padding: 0; list-style: none; 清除浏览器默认样式 .father1 { width: 400px; height: 400p…

    数据库 2023年6月11日
    099
  • 2022-8-26 jq简单了解

    Query 是一个 JavaScript 函数库。 jQuery 是一个轻量级的”写的少,做的多”的 JavaScript 库。jQuery 库包含以下功能…

    数据库 2023年6月14日
    0120
  • Java面试题(十)–Spring Cloud

    1 基础知识篇 1、什么是微服务架构? 微服务架构是一种架构模式或者说是架构风格,它提倡将单一应用程序划分成一组小的服务。每个服务运行在其独立的自己的进程中服务之间相互配合、相互协…

    数据库 2023年6月16日
    0103
  • 第十章 对象的生命周期

    1.什么是生命周期 对象创建 存活 销毁的完整的过程 2.为什么学习对象的生命周期 在以前通过new创建对象,调用对象,则该对象存活,直到被JVM的垃圾回收机制回收 现在由Spri…

    数据库 2023年6月14日
    089
  • 重写Feign编码器

    有个spring cloud 架构的项目需要调用php小组的api接口,但php提供的接口入参大部分是下划线命名,而Java这边的实体类是按照驼峰编写,如果使用Fegin调用会导致…

    数据库 2023年6月6日
    082
  • 在 Pisa-Proxy 中,如何利用 Rust 实现 MySQL 代理

    一、前言 背景 在 Database Mesh 中,Pisanix 是一套以数据库为中心的治理框架,为用户提供了诸多治理能力,例如:数据库流量治理,SQL 防火墙,负载均衡和审计等…

    数据库 2023年6月16日
    0132
  • 【Java基础】 — Java遍历List四种方法的效率对比 【转载】

    1.遍历方法简介 Java遍历List的方法主要有四种: *for each *Iterator *loop without size *loop with size 注:这里我们…

    数据库 2023年6月6日
    0128
  • 一,Flink快速上手

    1.依赖配置 1.1 pom文件 8 8 1.13.0 1.8 2.12 1.7.30 org.apache.flink flink-java ${flink.version} o…

    数据库 2023年6月6日
    094
  • Excel文件校验

    工作中,经常存在excel文件的导入导出的相关工作,因此正确的文件格式校验成为必须。不合适的文件校验方式会导致非法文件跳过校验,从而产生不必要的麻烦。比如,通过文件后缀名的方式进行…

    数据库 2023年6月14日
    0144
  • Maven项目POM文件设置依赖

    https://www.cnblogs.com/stars-one/p/10958796.html 可以参考这个链接 这里个添加依赖 如果在如上界面找不到 请设置一下本地仓库 Or…

    数据库 2023年6月9日
    0116
  • vim+vundle配置

    Linux环境下写代码虽然没有IDE,但通过给vim配置几个插件也足够好用。一般常用的插件主要包括几类,查找文件,查找符号的定义或者声明(函数,变量等)以及自动补全功能。一般流程都…

    数据库 2023年6月9日
    089
  • apk生成多渠道的安装包

    一、前言->需求 最近公司的项目需要试上线,安卓包会放到多个渠道进行推广,玩家会进行下载安装登录,后台为了得到渠道包的下载使用数据,就会给每个渠道包加入了不同的渠道ID以便统…

    数据库 2023年6月14日
    0111
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球