文章目录

  • 1 SimpleDateFormat介绍
  • 2 线程不安全的原因
  • 3 错误信息
    • 3.1 parse报错
      • 3.1.1 异常信息
      • 3.1.3 计算错误信息
    • 3.2 format报错
  • 4 解决方案
    • 4.1 每次创建新的DateFormat
    • 4.2 线程内变量ThreadLocal
    • 4.2 线程安全的 DateTimeFormatter

1 SimpleDateFormat介绍

SimpleDateFormat是DateFormat类的主要子类,用于日期格式的转换。

2 线程不安全的原因

DateFormat类中,有个protected的属性calendar,用于存储设置的时间

/*** The {@link Calendar} instance used for calculating the date-time fields* and the instant of time. This field is used for both formatting and* parsing.** <p>Subclasses should initialize this field to a {@link Calendar}* appropriate for the {@link Locale} associated with this* <code>DateFormat</code>.* @serial*/protected Calendar calendar;

翻译过来就是:

用于计算日期-时间字段的{@link Calendar}实例和时间的瞬间。此字段用于格式化和解析。

子类应该将这个字段初始化为Calendar适用于与此关联的Locale

DateFormat中提供了很多共有方法去更改此属性,如下:

public void setCalendar(Calendar newCalendar)
{this.calendar = newCalendar;
}
public void setTimeZone(TimeZone zone)
{calendar.setTimeZone(zone);
}

即DateFromat中存有当前将要转换的时间信息,而不只是格式化相关的信息

如将DateFormat设置为一个全局变量。时间转换都使用此变量进行转换,每次转换时间,都将更改此全局对象中的calendar信息

多线程情况下会导致线程不安全的问题,即一个线程更改此属性后,在计算格式化或者换行成日期的过程中,其他线程对此属性进行了更改,导致计算报错,或者计算不正确。

此处说明下:

DateFormat本身设计的方式就不是多线程安全的。

我们常说SimpleDateFormat不是多线程安全的,其实指的就是DateFormat的问题。在JDK中SimpleDateFormat是DateFormat的唯一子类

其他ja包中也存在DateFormat的子类,使用时也需要注意线程安全的问题,如poi中的org.apache.poi.ss.usermodel.ExcelStyleDateFormatter

3 错误信息

多线程环境下使用SimpleDateFormat进行日期转换,会出现两种错误信息:

(1)抛出异常

(2)计算错误

3.1 parse报错

测试多线程环境的的SimpleDateFormat的parse操作。

执行如下代码,进行多线程环境下的日期转换:

public class NumberFormatErrorTest {public static final DateFormat DATE_FORMAT=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static void main(String[] args) {for(int i=0;i<100;i++){new Thread(() -> {try {Date date=DATE_FORMAT.parse("2020-04-04 12:00:00");System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));}catch (Exception e){e.printStackTrace();}}).start();}}
}
3.1.1 异常信息
  • 报错1

java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
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:2056)
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.sa.module.test.threadlocal.NumberFormatErrorTest.lambda$main$0(NumberFormatErrorTest.java:18)
at java.lang.Thread.run(Thread.java:745)

  • 报错2

java.lang.NumberFormatException: For input string: “E.420022E”
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:2056)
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.sa.module.test.threadlocal.NumberFormatErrorTest.lambda$main$0(NumberFormatErrorTest.java:18)
at java.lang.Thread.run(Thread.java:745)

  • 报错3

java.lang.NumberFormatException: For input string: “”
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
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.sa.module.test.threadlocal.NumberFormatErrorTest.lambda$main$0(NumberFormatErrorTest.java:18)
at java.lang.Thread.run(Thread.java:745)

3.1.3 计算错误信息

按照上述代码,输出的日期,都应该为2020-04-04 12:00:00,但是多线程环境下运行,出现如下错误的计算结果:

2020-03-31 12:00:00

2020-04-04 00:00:00

2031-10-02 12:00:00

4202-04-04 12:00:00

可以看出,多线程情况下,SimpleDateFormat的计算结果,存在很大一部分几率计算错误,而且计算结果都是未知的。

3.2 format报错

待验证。。。。。。

4 解决方案

4.1 每次创建新的DateFormat

每次新线程内的操作,需要用到SimpleDateFormat时,都new 新的。

public class NumberFormatOk1Test {public static void main(String[] args) {for(int i=0;i<100;i++){new Thread(() -> {try {DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date=dateFormat.parse("2020-04-04 12:00:00");System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));}catch (Exception e){e.printStackTrace();}}).start();}}
}

4.2 线程内变量ThreadLocal

public class NumberFormatOk2Test {private static final ThreadLocal<DateFormat> THREAD_LOCALE=new ThreadLocal<DateFormat>(){@Overrideprotected DateFormat initialValue() {return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");}};public static void main(String[] args) {for(int i=0;i<100;i++){new Thread(() -> {try {Date date=THREAD_LOCALE.get().parse("2020-04-04 12:00:00");System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));}catch (Exception e){e.printStackTrace();}finally {THREAD_LOCALE.remove();}}).start();}}
}

4.2 线程安全的 DateTimeFormatter

JDK8中提供了线程安全的日期转换类DateTimeFormatter。

SimpleDateFormat线程不安全及解决方案相关推荐

  1. SimpleDateFormat 线程不安全及解决方案

    SimpleDateFormat 线程不安全及解决方案 参考文章: (1)SimpleDateFormat 线程不安全及解决方案 (2)https://www.cnblogs.com/yangzhen ...

  2. SimpleDateFormat线程不安全了?这里有5种解决方案

    摘要:我们知道SimpleDateFormat是线程不安全,本文会介绍多种解决方案来保证线程安全. 本文分享自华为云社区<java的SimpleDateFormat线程不安全出问题了,虚竹教你多 ...

  3. 丢失的8小时去哪里了?SimpleDateFormat线程不安全,多线程初始化异常解决方案

    前言 本次参加了2月份的征文活动,说是对时间的处理问题,我这有2个点需要分享一下,一个是上大学的时候碰到的,还有就是在工作中遇到的由于[SimpleDateFormat线程不安全]在多线程时间初始化的 ...

  4. hashmap是线程安全的吗?怎么解决?_解决SimpleDateFormat线程安全问题

    SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须通过加锁等方式保证线程安全. 例如下面一段代码,启动10个线程,同时使用一个`Simple ...

  5. SimpleDateFormat线程不安全及解决办法

    昨天知道了findbugs这个工具 而且用这个工具找到了潜在几个问题,有一个是便利map用的keyset  findbugs建议改成entrtyset,还有一个就是 SimpleDateFormat不 ...

  6. SimpleDateFormat线程不安全

    SimpleDateFormat线程不安全 http://www.cnblogs.com/peida/archive/2013/05/31/3070790.html dateUtil替换 posted ...

  7. 为什么SimpleDateFormat线程不安全? 侵立删

    转自:https://mp.weixin.qq.com/s/2uzr800WYtu4R0hycfGruA 在日常开发中,我们经常会用到时间相关类,我们有很多办法在Java代码中获取时间.但是不同的方法 ...

  8. Java基础学习总结(143)——SimpleDateFormat线程安全问题重现、原因分析及解决方案

    分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!点击浏览教程 一.SimpleDateFormat作用: 进行时间的格式化输出和解析(注意:Sim ...

  9. java中SimpleDateFormat线程安全问题及解决方案

    最近看到一篇文章提到了SimpleDateFormat这个类.说这个类在单线程程序中没问题,但是在多线程环境下会线程安全的问题. 出于兴趣对这个问题进行了查证.网上有很多关于这个问题的文章,也解析了其 ...

最新文章

  1. 1022 Digital Library
  2. hdu 2516 FIB博弈模型
  3. 如何将一个数组对象 把对象的值用指定符号连接起来 再转为数组 将数组用逗号分隔...
  4. php7 redis长连接,php使用redis长连接有哪些步骤
  5. Fragment:support.v4.content.Loader.deliverResult
  6. 米聊PK微信:微信是一朵奇葩
  7. 2020年国家电网计算机类考纲,终于发布!详解2020届国家电网考试大纲,带你读懂考纲变化!...
  8. 工业以太网交换机的作用和工作原理详解
  9. python 二进制数 转字符串_Python二进制串转换为通用字符串的方法
  10. java linux 调用32位so_从linux源码看socket(tcp)的timeout
  11. AnyTrans使用教程:将照片从 Mac 传输到 iPhone 的方法
  12. Could not resolve placeholder jdbc.driver in string value ${jdbc.driver}
  13. 13. Element childNodes 属性
  14. MAC安装ant的办法
  15. android7.1.2 xposed,安卓7.1 xposed框架
  16. 【科学文献计量】Metaknowledge文献数据分析基础(Record、Citation和RecordCollection对象介绍)
  17. Python-Leetcode-剑指offer(五月上做题整理)
  18. 剖析搜索引擎背后的经典数据结构和算法
  19. 第九篇:人生中哪些是对错的选择?
  20. clion_gcc报错

热门文章

  1. Ubuntu16.04上安装SU(Seismic Unix)的基本步骤
  2. MultiMedia eXtensions - MMX:第一套应用于英特尔 80x86 指令集的 SIMD 扩展
  3. int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
  4. DPDK 网卡收包流程
  5. 关于布隆过滤器的所有信息:利用Hash实现的索引方案
  6. python 字符串替换多个_python同时替换多个字符串方法示例
  7. 百度地图获取河流_想要提高学生对地理的兴趣,就要多利用地图,培养学生的思维能力...
  8. python基础布尔和None(三)
  9. oracle erp crm系统,企业集成ERP和CRM系统的模式体验
  10. java 跳表_跳表 skiplist