「日常开发」记一次因使用Date引起的线上BUG处理

生活中,我们需要掌控自己的时间,减少加班,提高效率;日常开发中,我们需要操作时间API,保证效率、安全、稳定。现在都2020年了,了解如何在JDK8及以后的版本中更好地操控时间就很有必要,尤其是一次线上BUG的发生,让小明更是深有体会。

背景

Java8以前,每每操控时间,我们经常使用的类库就是 Date,并且会通过 SimpleDateFormat类对时间进行格式化。你可知道? Date类是一个可变类, SimpleDateFormat类也是线程不安全的,因此在多线程的场景下执行格式化操作时,就会发生意想不到的情况。下面我们看一下使用 DateSimpleDateFormat在多线程下可能发生的问题以及使用 LocalDateTimeDateTimeFormatter的方法和优势。

问题来了

多线程环境下,使用 DateSimpleDateFormat时,如果我们将它定义为一个静态变量使用,虽然会避免重复创建实例, 但是会出现个别线程获取时间失败的现象,我们通过代码模拟这个场景:

「日常开发」记一次因使用Date引起的线上BUG处理

运行 main方法,查看控制台会发现有个别线程会报 java.lang.NumberFormatException异常。类似下图所示:

「日常开发」记一次因使用Date引起的线上BUG处理

问题分析

接下来,我们通过查看源码进一步分析(多图预警),可以看到 SimpleDateFormat是直接继承的 DateFormat类:

「日常开发」记一次因使用Date引起的线上BUG处理

首先是 SimpleDateFormatparse()方法,该方法中创建了一个 CalendarBuilder对象,

「日常开发」记一次因使用Date引起的线上BUG处理

再往下看,会看到 CalendarBuilder使用 establish方法将变量 calendar设值到其属性中,

image-20200420012213545

calendar是父类 DateFormat类的共享变量,可以被多个线程访问到

「日常开发」记一次因使用Date引起的线上BUG处理

因此当 SimpleDateFormat声明为 static时,线程并不安全,多个线程同时操作访问就会抛出异常。

同样地通过查看 format(),我们发现 format方法中有一行 calendar.setTime(date);也是操作的该共享变量 calendar,线程也是不安全的。

「日常开发」记一次因使用Date引起的线上BUG处理

有趣的是,在 DateFormat源码注释上作者也已经给出醒目的提示:

「日常开发」记一次因使用Date引起的线上BUG处理

使用Google翻译过来就是

日期格式不同步。 建议为每个线程创建单独的格式实例。 如果多个线程同时访问一种格式,则必须在外部同步该格式。

解决方案

小明有一句座右铭,方法总比问题多。我们来看几个小明认为不错的解决方案。

1、仅在需要用到的地方创建一个新的实例,就没有线程安全问题。

点评:加重了创建对象的负担,频繁地创建和销毁对象,消耗资源,效率较低。

2、通过 synchronized 解决线程安全问题;

点评:并发量大的时候会对性能有影响,容易造成线程阻塞。

3、通过ThreadLocal保证线程之间变量不共享

点评:ThreadLocal可以确保每个线程都可以得到单独的一个 SimpleDateFormat的对象,那么自然也就不存在竞争问题了。就是有点大材小用。

「日常开发」记一次因使用Date引起的线上BUG处理

以上就是小明能够提供的所有方案。什么,都不满意?我们来看一下2020年JDK8的解决方案。

使用 LocalDateTime

Java8以后,我们有了新的选择,使用 LocalDateTime时间类。首先, LocalDateTime本身是线程安全的,其对应的格式化工具类 DateTimeFormatter也是线程安全的,不存在变量共享,每一个属性字段都用了final关键字修饰,因此每次操作后都是返回的copy对象。并且 LocalDateTime类本身也有很多操作时间的API来替代传统的 Calendar类。

基于 Java8DateTimeFormatter的解决方案,我们对之前的代码进行改造,多线程环境下,运行代码,并未发现任何异常,稳定高效:

「日常开发」记一次因使用Date引起的线上BUG处理

我们可以看到 在DateTimeFormatter源码上作者也贴心的加注释说明,该类是不可变的,并且是线程安全的。

「日常开发」记一次因使用Date引起的线上BUG处理

同理,这点我们也可以从 LocalDateTime的官方源码中看出。

其他骚操作

为了让大家忘掉之前使用 Calendar操作时间的笨拙,我们来切实感受一下 LocalDateTime给实际开发中带来的便利:

「日常开发」记一次因使用Date引起的线上BUG处理

更多举例说明,请点击文末阅读原文
代码地址:https://github.com/WhenCoding/coder-xiaoming

总结

综上,小明推荐小伙伴们使用JDK8的 LocalDateTime系列来取代 Date系列,这样做不仅能够保证线上项目平稳运行,而且通过其自带的API还能操作时间,还能提高开发效率,今晚可以不加班!

欢迎大家访问我的个人博客网站:https://mynamecoder.com

Original: https://www.cnblogs.com/coderxx/p/12741716.html
Author: Coder小明
Title: 「日常开发」记一次因使用Date引起的线上BUG处理

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

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

(0)

大家都在看

  • Elasticsearch5.0 安装问题集锦

    elasticsearch 5.0 安装过程中遇到了一些问题,通过查找资料几乎都解决掉了,这里简单记录一下 ,供以后查阅参考,也希望可以帮助遇到同样问题的你。 问题一:警告提示 […

    技术杂谈 2023年6月1日
    086
  • MySQL数据库-数据表(二)

    分析:给 reader 表添加数据. INSERT INTO:插入数据,插入数据的时候会检查主键或者唯一索引,如果出现重复就会报错; 语法:INSERT INTO table_na…

    技术杂谈 2023年6月21日
    097
  • quartz框架(七)-JobStore

    在之前的博文中,博主已经写了关于Job的相关内容。本篇博文,博主将介绍JobStore相关的内容。 JobStore是存放Job和Trigger的地方。当我们调用Scheduler…

    技术杂谈 2023年7月24日
    071
  • pip安装之权限问题

    1、如果python安装在C盘的话,那么在通过pip安装模块时需要以管理员形式打开命令窗口去执行pip 安装命令 操作方法:按win+X 键,选择windows powershel…

    技术杂谈 2023年7月11日
    082
  • 2-第一个Django程序

    第一个Django程序 从本章节开始将通过实现一个投票应用程序,来让用户逐步的了解Django。这个程序由两步分组成: 公共站点,允许用户访问进行投票,和查看投票。 站点管理,允许…

    技术杂谈 2023年7月10日
    0100
  • 技术管理进阶——管理者可以使用哪些管理工具

    原创不易,求分享、求一键三连 前段时间有个粉丝问了一个问题: 小钗,成为Leader后,我到底有什么管理工具可以使用呢? 很好的问题,其实前文已经介绍了组织执行力的三要素:意愿、能…

    技术杂谈 2023年6月1日
    076
  • 解决 IdentityServer 授权与登录分离的问题

    园子 open api (api.cnblogs.com) 的授权服务器(authorization server,oauth.cnblogs.com)基于 IdentyServe…

    技术杂谈 2023年5月31日
    0102
  • 【全网最全的博客美化系列教程】19.旋转立方体的实现

    【全网最全的博客美化系列教程】09.添加”扩大/缩小浏览区域大小” 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列…

    技术杂谈 2023年5月31日
    084
  • Kubernetes(k8s)中dashboard的汉化

    1、访问服务器的http://192.168.110.133:8080/ui地址,如下所示: 使用dashboard版本registry.cn-hangzhou.aliyuncs….

    技术杂谈 2023年5月31日
    081
  • Flink学习笔记(整理)

    Fink简介 简单入门 Flink安装部署 Standalone模式 Yarn模式 Kubernetes部署 Flink运行架构 运行时四大组件 任务提交流程 任务调度原理 Fli…

    技术杂谈 2023年7月11日
    069
  • Java — 注解

    Java 注解(Annotation)又称为 Java 标注,是 Java5 开始支持加入源代码的特殊语法元数据。 Java 语言中的类、方法、变量、参数和包等都可以被标注。 Ja…

    技术杂谈 2023年7月11日
    070
  • 通过示例学习PYTORCH

    核心是:PyTorch提供了两个主要的特性: 一个n维的Tensor,与Numpy相似但可以在GPU上运行 构建和训练神经网络的自动微分 我们将使用一个三阶多项式拟合 (y=sin…

    技术杂谈 2023年7月25日
    090
  • java se 高级基础

    接口 继承树 Collection接口 Map接口 Collection 接口 Collection接口:单列集合,用来存储一个一个的对象 List接口:extends Colle…

    技术杂谈 2023年6月21日
    072
  • Property Trees & DispalyItem

    版权声明:本文为CSDN博主「tornmy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/…

    技术杂谈 2023年5月31日
    084
  • 多重背包问题的单调队列优化

    多重背包问题的单调队列优化 温馨提示:先吃甜点,再进入正餐食用更佳噢~ 0-1背包问题(餐前甜点) https://www.acwing.com/problem/content/2…

    技术杂谈 2023年7月11日
    077
  • Python——静态方法、类方法、公有方法、私有方法

    普通实例方法,第一个参数需要是self,它表示一个具体的实例本身。 静态方法是类中不需要实例的函数,无self,仅仅是类中的函数。可以由类实例或类调用。(1)使用staticmet…

    技术杂谈 2023年7月11日
    078
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球