今天一位优秀的架构师告诉我,下面这段代码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一定是线程不安全吗?的更多相关文章

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

    一直以来都是直接用SimpleDateFormat开发的,没想着考虑线程安全的问题,特记录下来(摘抄的): 1.问题: 先来看一段可能引起错误的代码: package test.date; impor ...

  2. SimpleDateFormat类的线程安全问题和解决方案

    摘要:我们就一起看下在高并发下SimpleDateFormat类为何会出现安全问题,以及如何解决SimpleDateFormat类的安全问题. 本文分享自华为云社区<SimpleDateForm ...

  3. SimpleDateFormat使用和线程安全问题

    SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (date -> text).语法分析 (text -> date)和标准化. Simpl ...

  4. 为什么SimpleDateFormat不是线程安全的?

    一.前言 日期的转换与格式化在项目中应该是比较常用的了,最近同事小刚出去面试实在是没想到被 SimpleDateFormat 给摆了一道... 面试官:项目中的日期转换怎么用的?SimpleDateF ...

  5. sdf SimpleDateFormat 不是线程安全的,

    我经常用一个public static SimpleDateFormat sdf; 今天发现报“java.lang.NumberFormatException: multiple points”的异常 ...

  6. SimpleDateFormat 的性能和线程安全性

    系统正常运行一段时间后,QA报给我一个异常: java.lang.OutOfMemoryError: GC overhead limit exceeded at java.text.DecimalFo ...

  7. SimpleDateFormat 的线程安全问题与解决方式

    SimpleDateFormat 的线程安全问题 SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的详细类. 它同意格式化 (date -> text).语法分析 (te ...

  8. 转:浅谈SimpleDateFormat的线程安全问题

    转自:https://blog.csdn.net/weixin_38810239/article/details/79941964 在实际项目中,我们经常需要将日期在String和Date之间做转化, ...

  9. SimpleDateFormat线程不安全及解决的方法

    一. 为什么SimpleDateFormat不是线程安全的? Java源代码例如以下: /** * Date formats are not synchronized. * It is recomme ...

随机推荐

  1. 08.手写KNN算法测试

    导入库 import numpy as np from sklearn import datasets import matplotlib.pyplot as plt 导入数据 iris = data ...

  2. 图片居中的flex实现

    文本居中 text-align:center; 如果是图片放在div中,就没办法了.用flex可以很简单实现. display: flex; justify-content: center; /* 图 ...

  3. 迭代器 (Iterator) 和 生成器 (Generator)

    其他章节请看: es6 快速入门 系列 迭代器 (Iterator) 和 生成器 (Generator) 试图解决的问题 let colors = ['red', 'blue', 'green', ' ...

  4. 【图像处理】使用OpenCV进行图像处理教程(一)

    OpenCV是进行图像处理的工具,也是计算机视觉领域近十几年不断发展和完善的产物.面对这个已基本成熟的开源库知识体系,我们新生代有必要不断地总结.回顾,以新的视角快速融入计算机视觉的奥秘世界. 从这篇 ...

  5. Hi3559AV100 SDK的详细安装过程及问题解决方法

    下面给出Hi3559AV100 SDK的安装的详细步骤(一些注意事项可以参照我之前写的随笔-<Hi3519 SDK搭建.问题总结及yolov3 RFCN的运行结果与测试 >): 1.开发环 ...

  6. javascript处理HTML的Encode(转码)和解码(Decode)

    HTML的Encode(转码)和解码(Decode)在平时的开发中也是经常要处理的,在这里总结了使用javascript处理HTML的Encode(转码)和解码(Decode)的常用方式 一.用浏览器 ...

  7. 让人头疼的AI bug (随想)

    虽然概念上,人工智能和机器学习不等同.但是本文提及的AI,指的是基于机器学习的AI.   一个软件产品,出了错误叫bug,bug需要修.那一个机器学习的模型,准确率在那摆着呢,大伙心知肚明是有一定的犯 ...

  8. docker nacos 集群部署

    1.准备机器3台 192.168.101.14 192.168.101.15 192.168.101.16 2.初始化sql(如果我们要搭建集群的话,那么肯定是不能用内嵌的数据库,不然数据无法共享.集 ...

  9. LNMP配置——Nginx配置 —— 默认虚拟主机

    一.配置 首先修改配置文件 #vi /usr/local/nginx/conf/nginx.conf 在最后一个结束符号}前加一行配置: include vhost/*.conf; 意思就是/usr/ ...

  10. innerHTML,innerText

    文本替换 <p id="p1">Hello World!</p><div>神经</div><h3 class="hh ...