SimpleDateFormat一定是线程不安全吗?
今天一位优秀的架构师告诉我,下面这段代码SimpleDateFormat是线程不安全的。
/**
* 将Date按格式转化成String
*
* @param date Date对象
* @param pattern 日期类型
* @return String
*/
public static String date2String(Date date, String pattern) {
if (date == null || pattern == null) {
return null;
}
return new SimpleDateFormat(pattern).format(date);
}

那么let us test!
简单介绍下我的测试方法
1.时间转字符串
2.字符串转时间
3.时间转字符串
比较第一个字符串和第二个字符是否相同。如果没有并发问题,那么第一个字符串跟第二个字符串肯定完全一样
第一种情况
一个SimpleDateFormat实例,并发执行。
private static void newSimpleDate() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(1000));
while (true) {
poolExecutor.execute(new Runnable() {
@Override
public void run() {
String dateString = simpleDateFormat.format(new Date());
try {
Date parseDate = simpleDateFormat.parse(dateString);
String dateString2 = simpleDateFormat.format(parseDate);
if (!dateString.equals(dateString2)) {
System.out.println(dateString.equals(dateString2));
}
} catch (ParseException e) {
e.printStackTrace();
}
}
});
}
结果:
false
false
false
false
false
false
false
说明存在线程不安全的问题。
第二种情况
每次新建一个SimpleDateFormat 对象
private static void oneSimpleDate() {
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES,
new LinkedBlockingQueue<>(1000));
while (true) {
poolExecutor.execute(new Runnable() {
@Override
public void run() {
try {
date2String(new Date(), "yyyy-MM-dd HH:mm:ss");
} catch (ParseException e) {
e.printStackTrace();
}
}
});
}
}
public static void date2String(Date date, String pattern) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
String dateString = new SimpleDateFormat(pattern).format(date);
Date parseDate = simpleDateFormat.parse(dateString);
String dateString2 = simpleDateFormat.format(parseDate);
System.out.println(dateString.equals(dateString2));
}
结果:永远为true
true
true
true
true
true
true
true
说明没有线程安全问题。
奇怪,那么SimpleDateFormat究竟有没有问题呢?
简单看一下SimpleDateFormat.format()方法。
protected Calendar calendar;
public StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition pos)
{
pos.beginIndex = pos.endIndex = 0;
return format(date, toAppendTo, pos.getFieldDelegate());
} // Called from Format after creating a FieldDelegate
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date); boolean useDateFormatSymbols = useDateFormatSymbols(); for (int i = 0; i < compiledPattern.length; ) {
int tag = compiledPattern[i] >>> 8;
int count = compiledPattern[i++] & 0xff;
if (count == 255) {
count = compiledPattern[i++] << 16;
count |= compiledPattern[i++];
} switch (tag) {
case TAG_QUOTE_ASCII_CHAR:
toAppendTo.append((char)count);
break; case TAG_QUOTE_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break; default:
subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
break;
}
}
return toAppendTo;
}
可以看到,多个线程之间共享变量calendar,并修改calendar。因此在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象(如static修饰)的话,如调用format方法时,多个线程会同时调用calender.setTime方法,导致time被别的线程修改,因此线程是不安全的。此外,parse方法也是线程不安全的。
SimpleDateFormat不是线程安全的,但这并不代表,它无法被线程安全的使用,当你把它作为局部变量,每次新建一个实例,或者加锁,或者采用架构师说的DateTimeFormatter都能规避这个问题。
就像hashmap,大家都知道他是线程不安全的,在jdk1.7采用头插法时,并发会出现死循环。但是你每次new hashmap对象,去put肯定不会有问题,尽管不会有人这么用,业务也不允许。
所以,这件事告诉我们,不要守着自己的教条主义,看到线程不安全的类,就觉得方法是线程不安全的,要看具体的使用场景;当然线程安全的类,也有可能是线程不安全的;架构师也不例外喔!
SimpleDateFormat一定是线程不安全吗?的更多相关文章
- 关于 SimpleDateFormat 的非线程安全问题及其解决方案
一直以来都是直接用SimpleDateFormat开发的,没想着考虑线程安全的问题,特记录下来(摘抄的): 1.问题: 先来看一段可能引起错误的代码: package test.date; impor ...
- SimpleDateFormat类的线程安全问题和解决方案
摘要:我们就一起看下在高并发下SimpleDateFormat类为何会出现安全问题,以及如何解决SimpleDateFormat类的安全问题. 本文分享自华为云社区<SimpleDateForm ...
- SimpleDateFormat使用和线程安全问题
SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (date -> text).语法分析 (text -> date)和标准化. Simpl ...
- 为什么SimpleDateFormat不是线程安全的?
一.前言 日期的转换与格式化在项目中应该是比较常用的了,最近同事小刚出去面试实在是没想到被 SimpleDateFormat 给摆了一道... 面试官:项目中的日期转换怎么用的?SimpleDateF ...
- sdf SimpleDateFormat 不是线程安全的,
我经常用一个public static SimpleDateFormat sdf; 今天发现报“java.lang.NumberFormatException: multiple points”的异常 ...
- SimpleDateFormat 的性能和线程安全性
系统正常运行一段时间后,QA报给我一个异常: java.lang.OutOfMemoryError: GC overhead limit exceeded at java.text.DecimalFo ...
- SimpleDateFormat 的线程安全问题与解决方式
SimpleDateFormat 的线程安全问题 SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的详细类. 它同意格式化 (date -> text).语法分析 (te ...
- 转:浅谈SimpleDateFormat的线程安全问题
转自:https://blog.csdn.net/weixin_38810239/article/details/79941964 在实际项目中,我们经常需要将日期在String和Date之间做转化, ...
- SimpleDateFormat线程不安全及解决的方法
一. 为什么SimpleDateFormat不是线程安全的? Java源代码例如以下: /** * Date formats are not synchronized. * It is recomme ...
随机推荐
- sklearn中的pipeline实际应用
前面提到,应用sklearn中的pipeline机制的高效性:本文重点讨论pipeline与网格搜索在机器学习实践中的结合运用: 结合管道和网格搜索以调整预处理步骤以及模型参数 一般地,sklearn ...
- rabbitMQ高可用方案
普通模式 默认的集群模式,以两个节点(rabbit01.rabbit02)为例来进行说明.对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和r ...
- 进阶高阶IoT架构-教你如何简单实现一个消息队列
前言 消息队列是软件系统领域用来实现系统间通信最广泛的中间件.基于消息队列的方式是指由应用中的某个系统负责发送消息,由关心这条消息的相关系统负责接收消息,并在收到消息后进行各自系统内的业务处理.消息可 ...
- SpringBoot 项目初始化
工作之余,想要学习一下SpringBoot,通过网络大量教程最终成功运行SpringBoot项目. 第一步 首先,通过教程发现一套完整的快速搭建SpringBoot项目网站:https://star ...
- JavaWeb实现用户登录注册功能实例代码(基于Servlet+JSP+JavaBean模式)
一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...
- 看完我的笔记不懂也会懂----MongoDB
MongoDb数据库学习 - 数据库的分类 - 数据库基本概念 - MongoDB常用指令 - MongoDB的CURD - sort({key:*[1,-1]}).limit(num).skip(n ...
- css实现鼠标滑过出现从中间向两边扩散的下划线
这个效果一开始我是在华为商城页面上看到的,刚开始还以为挺复杂,实现的时候还有点没头绪.不过,还好有百度,借此记录一下我在导航条上应用的实现方法. 主要是借助了伪元素,代码如下: <div cla ...
- List调用toString()方法后,去除两头的中括号
import org.apache.commons.lang.StringUtils; public class Test { public static void main(String[] ...
- FreeBSD 如何安装软件
1:概括FreeBSD捆绑了丰富的系统工具集合作为基础系统的一部分.此外,FreeBSD提供了两种用于安装第三方软件的补充技术:FreeBSD Ports Collection,用于从源代码安装,以及 ...
- Java 使用BigDecimal计算值没有变化?
BigDecimal 加减乘除后自身变量不会变化, 需要定义一个新的BigDecimal来获取计算好后的值