`

SimpleDateFormat是线程不安全的

阅读更多

概述

最近在搞大数据实时计算,期间在解析时经常会用到 SimpleDateFormat对时间进行格式化。通过观察每天的日志经常会发现下列异常:

java.lang.NumberFormatException: For input string: ""
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
        at java.lang.Long.parseLong(Long.java:431)
        at java.lang.Long.parseLong(Long.java:468)
        at java.text.DigitList.getLong(DigitList.java:177)
        at java.text.DecimalFormat.parse(DecimalFormat.java:1297)
        at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)
        at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1311)
        at java.text.DateFormat.parse(DateFormat.java:335)
        at com.xxxxxxx.core.common.util.DateUtil.parseTimestamp(DateUtil.java:95)
        at com.xxxxxxx.core.common.util.DateUtil.parse(DateUtil.java:84)
        at com.xxxxxxx.hbase.generator.LogRowKeyGenerator.generate(LogRowKeyGenerator.java:21)
        ... 22 more

 

 原因

通过查找资料发现SimpleDateFormat是继承自DateFormat类,该类中直接使用了Calendar成员变量,该变量在多线程中共享,是线程不安全的,关于线程安全可以参考这里

protected Calendar calendar;

而我们实际中经常在常量类中定义一个如下的对象:

public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

 在多线程中使用DATE_FORMAT.parse(str)、DATE_FORMAT.format(str)就会遇到上述异常问题。

 究其原因,可以看下SimpleDateFormat源码:

public Date parse(String text, ParsePosition pos)
    {
    
        checkNegativeNumberExpression();
    
        int start = pos.index;
        int oldStart = start;
        int textLength = text.length();
        ........//省略
        //establish方法中会调用 calendar.clear(); 
        parsedDate = calb.establish(calendar).getTime();
        ........//省略

        //采用text 重新给calendar赋值
        start = subParse(text, start, tag, count, obeyCount,
				 ambiguousYear, pos, useFollowingMinusSignAsDelimiter);
        
        ........//省略
        Date parsedDate = calendar.getTime();
        return parsedDate 
    }

 在多线程高并发情况下,A线程执行完成calendar.clear(),但还没有执行getTime(), B线程又执行calendar.clear()方法,当A线程执行getTime()就会报上述异常java.lang.NumberFormatException: For input string: ""。

 

报空指针只是其中一种情况,还会有些未知的错误,就是两个线程中的日期串改。

 

解决办法

我的解决办法就是每次都new SimpleDateFormat()

在工具类中提供一个静态方法每次都new SimpleDateFormat():

public static DateFormat getSimpleDF(){
      return new SimpleDateFormat("yyyy-MM-dd");
}

也可以用ThreadLocal来解决在同一个线程中对 DateFormat进行复用,关于ThreadLocal可以参考这里

分享到:
评论

相关推荐

    simpleDateFormat是线程不安全的

    NULL 博文链接:https://flynndang.iteye.com/blog/711878

    ThreadLocal:如何优雅的解决SimpleDateFormat多线程安全问题

    目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date日期转String类型(format)SimpleDateFormat出现...事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...

    SimpleDateFormat线程不安全的5种解决方案.md

    SimpleDateFormat线程不安全的5种解决方案.md

    SimpleDateFormat线程不安全的5种解决方案.docx

    SimpleDateFormat线程不安全的5种解决方案.docx

    详解SimpleDateFormat的线程安全问题与解决方案

    主要介绍了SimpleDateFormat的线程安全问题与解决方案,非常不错,具有参考借鉴价值,需要的朋友可以参考下

    高并发之-SimpleDateFormat类的线程安全问题和解决方案.docx

    高并发之-SimpleDateFormat类的线程安全问题和解决方案.docx

    关于SimpleDateFormat的非线程安全问题及其解决方案.docx

    关于SimpleDateFormat的非线程安全问题及其解决方案.docx

    Java多线程编程的线程安全性.docx

    Java标准库中的一些类如ArrayList、HashMap和SimpleDateFormat,都是非线程安全的,在多线程环境下直接使用它们可能导致一些非预期的结果,甚至是一些灾难性的结果。一般来说,Java标准库中的类在其API文档中会说明...

    Java SimpleDateFormat线程安全问题原理详解

    主要介绍了Java SimpleDateFormat线程安全问题原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    深入理解Java:SimpleDateFormat安全的时间格式化

    SimpleDateFormat 是 Java 中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调试的问题,因为 DateFormat 和 SimpleDateFormat 类不都是线程安全的,在多线程...

    Java多线程环境下SimpleDateFormat类安全转换

    主要介绍了Java多线程环境下SimpleDateFormat类安全转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    软件安全监测报告.pdf

    这份软件安全监测报告主要是监测java开发程序中出现的安全问题,找了一个项目程序监测后出现的原版报告显示,在使用DES加解密的情况下,会被检测...还有关于SimpleDateFormat线程不安全的问题,都有详细解释及处理方法

    gonwalk#JavaAndBigData#各种坑1

    1. SimpleDateFormat 不是线程安全的 2.cache模型里面字段数据范围 3.字符串不变性 4.HashCode被设计用来提高性能

    findbug 错误日志文档

    findbug的错误日志文档... 上面的英文解释其实应该说得比较清楚,在Java文档中,已经明确说明了DateFormats 是非线程安全的,而在SimpleDateFormat的Jdk 的Source文件中,我们也找到这么一段注释,说明它不是线程安全的

    java大学实用教程课件

    4.安全 5.动态 1.4 java 与C/C++之关系 如果你学习过C++语言,你会感觉Java很眼熟,因为Java中许多基本语句的语法和C++一样,像常用的循环语句、控制语句等和C++几乎一样,但不要误解为Java是C++的增强版,Java...

    java面试题

    Collections是针对集合类的帮助类,它提供了一系列针对集合的搜索,排序,线程安全化等操作。 final、finally、finalize的区别? 答:final用于声明属性方法和类,分别表示:属性不可变,方法不可覆盖,类不可继承...

    leetcodelrucache-algorithm:算法学习和练习

    如何线程安全的使用 SimpleDateFormat jdk.volatilex VolatileArrays: volatile 例子 jdk.collection.union JDK: javaAPI 方式 取得集合的交并集 (或者apache的API) largedata 大数据相关算法 目录见 larg

    springboot整合websocket

    // concurrent 包的线程安全 Set,用来存放每个客户端对应的 MyWebSocket 对象。若要实现服务端与单一客户端通信的话,可以使用 Map 来存放,其中 Key 可以为用户标识 private static ConcurrentHashMap, ...

Global site tag (gtag.js) - Google Analytics