SimpleDateFormat线程不安全及解决方案
文章目录
- 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线程不安全及解决方案相关推荐
- SimpleDateFormat 线程不安全及解决方案
SimpleDateFormat 线程不安全及解决方案 参考文章: (1)SimpleDateFormat 线程不安全及解决方案 (2)https://www.cnblogs.com/yangzhen ...
- SimpleDateFormat线程不安全了?这里有5种解决方案
摘要:我们知道SimpleDateFormat是线程不安全,本文会介绍多种解决方案来保证线程安全. 本文分享自华为云社区<java的SimpleDateFormat线程不安全出问题了,虚竹教你多 ...
- 丢失的8小时去哪里了?SimpleDateFormat线程不安全,多线程初始化异常解决方案
前言 本次参加了2月份的征文活动,说是对时间的处理问题,我这有2个点需要分享一下,一个是上大学的时候碰到的,还有就是在工作中遇到的由于[SimpleDateFormat线程不安全]在多线程时间初始化的 ...
- hashmap是线程安全的吗?怎么解决?_解决SimpleDateFormat线程安全问题
SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须通过加锁等方式保证线程安全. 例如下面一段代码,启动10个线程,同时使用一个`Simple ...
- SimpleDateFormat线程不安全及解决办法
昨天知道了findbugs这个工具 而且用这个工具找到了潜在几个问题,有一个是便利map用的keyset findbugs建议改成entrtyset,还有一个就是 SimpleDateFormat不 ...
- SimpleDateFormat线程不安全
SimpleDateFormat线程不安全 http://www.cnblogs.com/peida/archive/2013/05/31/3070790.html dateUtil替换 posted ...
- 为什么SimpleDateFormat线程不安全? 侵立删
转自:https://mp.weixin.qq.com/s/2uzr800WYtu4R0hycfGruA 在日常开发中,我们经常会用到时间相关类,我们有很多办法在Java代码中获取时间.但是不同的方法 ...
- Java基础学习总结(143)——SimpleDateFormat线程安全问题重现、原因分析及解决方案
分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!点击浏览教程 一.SimpleDateFormat作用: 进行时间的格式化输出和解析(注意:Sim ...
- java中SimpleDateFormat线程安全问题及解决方案
最近看到一篇文章提到了SimpleDateFormat这个类.说这个类在单线程程序中没问题,但是在多线程环境下会线程安全的问题. 出于兴趣对这个问题进行了查证.网上有很多关于这个问题的文章,也解析了其 ...
最新文章
- 1022 Digital Library
- hdu 2516 FIB博弈模型
- 如何将一个数组对象 把对象的值用指定符号连接起来 再转为数组 将数组用逗号分隔...
- php7 redis长连接,php使用redis长连接有哪些步骤
- Fragment:support.v4.content.Loader.deliverResult
- 米聊PK微信:微信是一朵奇葩
- 2020年国家电网计算机类考纲,终于发布!详解2020届国家电网考试大纲,带你读懂考纲变化!...
- 工业以太网交换机的作用和工作原理详解
- python 二进制数 转字符串_Python二进制串转换为通用字符串的方法
- java linux 调用32位so_从linux源码看socket(tcp)的timeout
- AnyTrans使用教程:将照片从 Mac 传输到 iPhone 的方法
- Could not resolve placeholder jdbc.driver in string value ${jdbc.driver}
- 13. Element childNodes 属性
- MAC安装ant的办法
- android7.1.2 xposed,安卓7.1 xposed框架
- 【科学文献计量】Metaknowledge文献数据分析基础(Record、Citation和RecordCollection对象介绍)
- Python-Leetcode-剑指offer(五月上做题整理)
- 剖析搜索引擎背后的经典数据结构和算法
- 第九篇:人生中哪些是对错的选择?
- clion_gcc报错
热门文章
- Ubuntu16.04上安装SU(Seismic Unix)的基本步骤
- MultiMedia eXtensions - MMX:第一套应用于英特尔 80x86 指令集的 SIMD 扩展
- int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
- DPDK 网卡收包流程
- 关于布隆过滤器的所有信息:利用Hash实现的索引方案
- python 字符串替换多个_python同时替换多个字符串方法示例
- 百度地图获取河流_想要提高学生对地理的兴趣,就要多利用地图,培养学生的思维能力...
- python基础布尔和None(三)
- oracle erp crm系统,企业集成ERP和CRM系统的模式体验
- java 跳表_跳表 skiplist