还在用SimpleDateFormat格式化时间?小心经理锤你

场景

本来开开心心的周末时光,线上突然就疯狂报错,以为程序炸了,截停日志,发现是就是类似下述一段错误

java.lang.NumberFormatException: For input string: ".202006E.202006E44"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2089)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.github.springtools.SimpleDateFormatTest.lambda$null$0(Xxxxxxx.java:2020)
at java.lang.Thread.run(Thread.java:748)

定位到错误处,发现是一个时间格式化(SimpleDateFormat)的异常,一个时间格式化怎么会导致这种错误,还使得接口不能正常调用

测试

拉出来,使用模拟接口多线程的环境,单独进行测试.....

package com.github.springtools;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.stream.IntStream; public class SimpleDateFormatTest {
public static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd"); public static void main(String[] args) throws ParseException {
System.out.println(FORMAT.parse("2020-06-06"));
System.out.println("--------单个调用结束--------");
System.out.println("--------多线程调用开始--------"); IntStream.rangeClosed(0, 10)
.forEach(i -> new Thread(() -> {
try {
System.out.println(FORMAT.parse("2020-06-06"));
} catch (ParseException e) {
e.printStackTrace();
}
}).start());
}
}

输出

Sat Jun 06 00:00:00 CST 2020
--------单个调用结束--------
--------多线程调用开始--------
Sat Jun 06 00:00:00 CST 2020
Sat Jun 06 00:00:00 CST 2020
Exception in thread "Thread-7" Exception in thread "Thread-8" java.lang.NumberFormatException: For input string: ".202006E.202006E44"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)

罪魁祸手浮出水面,就是SimpleDateFormat的锅



线程不安全,去找Java文档里的SimpleDateFormat: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部进行同步。

解决方法

使用ThreadLocal

// ThreadLocal
public static final ThreadLocal<SimpleDateFormat> THREADLOCAL_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
IntStream.rangeClosed(0, 5)
.forEach(i -> new Thread(() -> {
try {
System.out.println("ThreadLocal:" + THREADLOCAL_FORMAT.get().parse("2020-06-06"));
} catch (ParseException e) {
e.printStackTrace();
}
}).start());

使用Java 8中的时间处理

public static final DateTimeFormatter JAVA8_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
IntStream.rangeClosed(0, 5)
.forEach(i -> new Thread(() -> {
try {
System.out.println("JAVA8_FORMATTER:" + JAVA8_FORMATTER.parse("2020-06-06"));
} catch (ParseException e) {
e.printStackTrace();
}
}).start());

总结

使用多线程的时候,一定要考虑到其调用到的实例变量,Java8中时间格式化DateTimeFormatter是用final修饰的,不可变类,所以是线程安全的,或者在线程中调用ThreadLocal也是可以的

还在用SimpleDateFormat格式化时间?小心经理锤你的更多相关文章

  1. SimpleDateFormat 格式化时间少了12个小时

    SimpleDateFormat 格式化时间少了12个小时 标签(空格分隔): java SimpleDateFormat H:一天中的小时数:0-23 h: am/pm 小时数: 1-12 publ ...

  2. java-使用SImpleDateFormat格式化时间输出

    之前有篇博客是使用NSDateFormatter来对时间进行格式化输出,但使用起来有点繁琐,今天介绍下最近刚刚使用的SimpleDateFormat. public class SimpleDateF ...

  3. 记一次使用SimpleDateFormat 格式化时间时遇到的问题

    网上的使用方法一大堆,我就不再介绍了,就写一下自己遇到的问题. 先来实现一下获取当前时间: SimpleDateFormat simpleDateFormat =new SimpleDateForma ...

  4. Java-Runoob-高级教程-实例-时间处理:01. Java 实例 - 格式化时间(SimpleDateFormat)

    ylbtech-Java-Runoob-高级教程-实例-时间处理:01. Java 实例 - 格式化时间(SimpleDateFormat) 1.返回顶部 1. Java 实例 - 格式化时间(Sim ...

  5. 【 格式化时间(SimpleDateFormat)用法】

    将特定字符串转换成Date格式 可以通过 new 一个 SimpleDateFormat 对象,通过对象调用parse方法实现 示例代码: String time = "2019-11-09 ...

  6. java 格式化时间

    java.text.DateFormat format1 = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); form ...

  7. SimpleDateFormat格式化日期

    SimpleDateFormat格式化日期 import java.text.SimpleDateFormat;import java.util.Date;public class test { pu ...

  8. JAVA格式化时间日期

    JAVA格式化时间日期 import java.util.Date; import java.text.DateFormat; /** * 格式化时间类 * DateFormat.FULL = 0 * ...

  9. Java格式化时间

    Java格式化时间 将秒或者毫秒值格式化成指定格式的时间 效果图 工具类 工具类里我只列出了一种格式的格式化方式,可以根据自己的需求,修改"yyyy-MM-dd hh:mm:ss" ...

随机推荐

  1. jmeter学习之安装篇(一)

    一.Jmeter简介 Jmeter是Apache组织开发的基于Java开源项目,设计之初是用于做性能测试的,同时它在实现对各种接口的调用方面做的比较成熟,因此,常被用做接口功能测试和性能测试. Jme ...

  2. mysql操作之二:fetchone与获取lastrowid

    import mySQLdb conn = mySQLdb.connect(host='127.0.0.1',user='root',passwd='123456')cur = conn.cursor ...

  3. Power安装linux-BIG ENDIAN mysql编译安装

    一.安装系统,不选择额外的软件 mkvdev -vadapter vhost0 -vdev hdisk2 -dev db_mysql01_sys mkvdev -vadapter vhost0 -vd ...

  4. Struts2导图

  5. Spring 基于 Java 的配置

    前面已经学习如何使用 XML 配置文件来配置 Spring bean. 基于 Java 的配置可以达到基于XML配置的相同效果. 基于 Java 的配置选项,可以使你在不用配置 XML 的情况下编写大 ...

  6. 解决CentOS无法识别网卡问题

    在联想电脑安装CentOS 6.9系统的时候,出现了无法上网问题,记录下这一路的坑. CentOS安装时在设置主机名这一步的下方有配置网络按钮,而此时该按钮点击无效.进入系统后发现没有网络连接. 在终 ...

  7. 还不会K8S吗?先从kubeadm开始吧

    目录 1. 准备工作 1.1 机器准备 1.2 系统配置 1.2.1 主机名及域名解析 1.2.2 免密登录 1.2.3 配置yum源 1.2.4 安装必要依赖包 1.2.5 关闭防火墙.SELinu ...

  8. 一言难尽,Jpa这个功能差点让我丢了工作

    故事背景 前阵子,有位朋友在微信上问我数据被删了能不能恢复,我问了下原因,居然是因为一个配置项惹的祸. 故事细节 在 Spring Boot 中使用 jpa 来操作数据库,jpa 就不做详细的介绍了, ...

  9. poi--读取不同类型的excel表格

    要想根据不同类型excel表格获取其数据,就要先判断其表格类型 poi-api种方法: getCellType    public int getCellType()        Return th ...

  10. Robot Framework(3)- 基本概念

    如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 在 RF ...