转:浅谈SimpleDateFormat的线程安全问题
转自:https://blog.csdn.net/weixin_38810239/article/details/79941964
在实际项目中,我们经常需要将日期在String和Date之间做转化,此时需要使用SimpleDateFormat类。使用SimpleDateFormat类的parse方法,可以将满足格式要求的字符串转换成Date对象,使用SimpleDateFormat类的format方法,可以将Date类型的对象转换成一定格式的字符串!但是有一点需要特别注意,SimpleDateFormat并非是线程安全的,也就是说在并发环境下,如果考虑不周使用SimpleDateFormat方法可以会出现线程安全方面的问题,需要我们特别注意!
下面展示下,SimpleDateFormat在并发环境下出现的问题!
No BB,Show Code!
运行环境:JDK1.8,引入maven依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
1- SimpleDateFormat线程安全问题
使用ExecutorService提交多个任务的方式,模拟并发环境将字符串转换为日期即测试parse方法,代码如下:
@Test
public void testParse() {
ExecutorService executorService = Executors.newCachedThreadPool();
List<String> dateStrList = Lists.newArrayList(
"2018-04-01 10:00:01",
"2018-04-02 11:00:02",
"2018-04-03 12:00:03",
"2018-04-04 13:00:04",
"2018-04-05 14:00:05"
);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
for (String str : dateStrList) {
executorService.execute(() -> {
try {
simpleDateFormat.parse(str);
TimeUnit.SECONDS.sleep();
} catch (Exception e) {
e.printStackTrace();
}
});
}
运行后,报错如下:

可见并发环境下使用SimpleDateFormat的parse方法有线程安全问题!
线程安全问题的原因:
在SimpleDateFormat转换日期是通过Calendar对象来操作的,SimpleDateFormat继承DateFormat类,DateFormat类中维护一个Calendar对象,代码如下


通过DateFormat类中的注释可知:此处Calendar实例被用来进行日期-时间计算,既被用于format方法也被用于parse方法!
在parse方法的最后,会调用CalendarBuilder的establish方法,入参就是SimpleDateFormat维护的Calendar实例,在establish方法中会调用calendar的clear方法,如下:

可知SimpleDateFormat维护的用于format和parse方法计算日期-时间的calendar被清空了,如果此时线程A将calendar清空且没有设置新值,线程B也进入parse方法用到了SimpleDateFormat对象中的calendar对象,此时就会产生线程安全问题!
2- 解决方案
每一个使用SimpleDateFormat对象进行日期-时间进行format和parse方法的时候就创建一个新的SimpleDateFormat对象,用完就销毁即可!代码如下:
/**
* 模拟并发环境下使用SimpleDateFormat的parse方法将字符串转换成Date对象
*/
@Test
public void testParseThreadSafe() {
ExecutorService executorService = Executors.newCachedThreadPool();
List<String> dateStrList = Lists.newArrayList(
"2018-04-01 10:00:01",
"2018-04-02 11:00:02",
"2018-04-03 12:00:03",
"2018-04-04 13:00:04",
"2018-04-05 14:00:05"
);
for (String str : dateStrList) {
executorService.execute(() -> {
try {
//创建新的SimpleDateFormat对象用于日期-时间的计算
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
simpleDateFormat.parse(str);
TimeUnit.SECONDS.sleep(1);
simpleDateFormat = null; //销毁对象
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
在运行可以发现不会报出之前的错误了!
综上所述,使用SimpleDateFormat对象进行日期-时间计算时,如果SimpleDateFormat是多个线程共享的就会有线程安全问题!应该让每一个线程都有一个独立的SimpleDateFormat对象用于日期-时间的计算!此时就可以使用ThreadLocal将SimpleDateFormat绑定到线程上,是的该线程上的日期-时间计算顺序的使用SimpleDateFormat对象,这样也可以避免线程安全问题!
转自:https://blog.csdn.net/weixin_38810239/article/details/79941964
转:浅谈SimpleDateFormat的线程安全问题的更多相关文章
- SimpleDateFormat的线程安全问题
做项目的时候查询的日期总是不对,花了很长时间才找到异常的根源,原来SimpleDateFormat是非线程安全的,当我把这个类放到多线程的环境下转换日期就会出现莫名奇妙的结果,这种异常找出来可真不容易 ...
- SimpleDateFormat 的线程安全问题与解决方式
SimpleDateFormat 的线程安全问题 SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的详细类. 它同意格式化 (date -> text).语法分析 (te ...
- 044 SimpleDateFormat的线程安全问题与解决方案
这个问题,以前好像写过,不过现在这篇文章,有一个重现的过程,还是值得读一读的. URL:SimpleDateFormat的线程安全问题与解决方案
- SimpleDateFormat的线程安全问题与解决方案
SimpleDateFormat 是 Java 中一个常用的类,该类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调试的问题. 因为 DateFormat 和 Simple ...
- struts 2学习笔记—浅谈struts的线程安全
Sruts 2工作流程: Struts 1中所有的Action都只有一个实例,该Action实例会被反复使用.通过上面Struts 2 的工作流程的红色字体部分我们可以清楚看到Struts 2中每个A ...
- 浅谈HashMap与线程安全 (JDK1.8)
HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型.HashMap 继承自 AbstractMap 是基于哈希表的 Map 接口的实现,以 Key-Value 的形式存在,即 ...
- 干货,阿里P8浅谈对java线程池的理解(面试必备)
线程池的概念 线程池由任务队列和工作线程组成,它可以重用线程来避免线程创建的开销,在任务过多时通过排队避免创建过多线程来减少系统资源消耗和竞争,确保任务有序完成:ThreadPoolExecutor ...
- 浅谈java中线程和操作系统线程
在聊线程之前,我们先了解一下操作系统线程的发展历程,在最初的时候,操作系统没有进程线程一说,执行程序都是串行方式执行,就像一个队列一样,先执行完排在前面的,再去执行后面的程序,这样的话很多程序的响应就 ...
- SimpleDateFormat非线程安全
文章列表 1)SimpleDateFormat的线程安全问题与解决方案 2)深入理解Java:SimpleDateFormat安全的时间格式化
随机推荐
- HEAD FILE
心血来潮做的沙雕Head,喜欢就拿去用吧,Explosion! HEAD //#pragma comment(linker, "/STACK:1024000000,1024000000&qu ...
- win10下maven的安装与配置
下载apache-maven-3.5.3-bin.zip并解压: 环境配置: 系统环境:添加=>MAVEN_HOME 值为apache-maven-3.5.3的路径(D:\xxx\apache- ...
- 老师博客copy -高阶函数2
新闻 管理 Py西游攻关之函数 一 函数是什么? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法.在B ...
- Lua中__index和__newindex实践
[具有默认值的table] 我们都知道,table中的任何字段的默认值都是nil,但是通过元表,我们可以很容易的修改这一规定,代码如下: function setDefault(tb, default ...
- Linux Django项目部署
步骤 .数据库的处理 1.1 上传bbs.sql 1.2 在mysql中创建bbs库,并导入数据库SQL脚本 mysql> create database bbs charset utf8mb4 ...
- 通过fiddler和逍遥模拟器模拟抓包android手机
环境说明 Fiddler/逍遥手机模拟器 安装在10.11.0.148的电脑中 逍遥模拟器会自动生成wifi连接到 10.11.0.148上网 开启https: 在模拟器中打开 http://代理:8 ...
- CentOS7.6 yum方式安装mysql2.7.25
在CentOS中默认安装有MariaDB,这个是MySQL的分支,但为了需要,还是要在系统中安装MySQL,而且安装完成之后可以直接覆盖掉MariaDB 1 下载并安装MySQL官方的 Yum Rep ...
- drop、truncate和delete的区别
TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行.但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源 ...
- SQL反模式学习笔记20 明文密码
目标:恢复或重置密码 反模式:使用明文存储密码 1.存储密码 使用明文存储密码或者在网络上传递密码是不安全的. 如果攻击者截取到你用来插入(或者修改)密码的sql语句,就可以获得密码. 黑客获 ...
- js 在echarts多条折线图数字*100 诡异出现小数
formatter:function(params){ //数据单位格式化 ].name; //x轴名称 , l = params.length; i < l; i++) { if(params ...