今天一位优秀的架构师告诉我,下面这段代码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. JS数组的常用属性或方法

    1.length 数组长度 计算数组的长度 var arr=[1,2,3,4,5]; console.log(arr.length);//输出结果是5 2. push() 添加元素 向数组尾部添加新元 ...

  2. ImportError: No module named _ssl解决方法

    import ssl时出现ImportError: No module named _ssl错误是因为咱安装Python的时候没有把ssl模块编译进去导致的. 解决步骤: 系统没有openssl,手动 ...

  3. 基于jQuery1.4.2轻量级的弹出窗口jQuery插件wBox 1.0

    Box特点 背景透明度可以根据实际情况进行调节 可以根据需要添加wBox标题 支持callback函数 支持html内容自定义 支持在wBox显示#ID的内容 支持Ajax页面内容 支持iFrame ...

  4. Github Fork与远程主分支同步

    fork与主分支同步(5步) 1. git remote add upstream git@github.com:haichong98/gistandard.git   新建一个upstream的远程 ...

  5. MongoDB -> kafka 高性能实时同步(sync 采集)mongodb数据到kafka解决方案

    写这篇博客的目的 让更多的人了解 阿里开源的MongoShake可以很好满足mongodb到kafka高性能高可用实时同步需求(项目地址:https://github.com/alibaba/Mong ...

  6. Python工程师学习之旅

    1.Python软件开发基础 1.Linux操作系统2.Docker基础3.Python基础语法4.Python字符串解析5.Python正则表达式6.Python文件操作7.Python 模块8.P ...

  7. [LeetCode 279.] Perfect Squres

    LeetCode 279. Perfect Squres DP 是笨办法中的高效办法,又是一道可以被好办法打败的 DP 题. 题目描述 Given a positive integer n, find ...

  8. 在linux下如何搭建jmeter的环境

    首先 我们可以选择不同版本的jmeter 转载原连接:https://blog.csdn.net/lyl0724/article/details/79474388 Jmeter历史版本下载地址 htt ...

  9. 使用自定义注解和切面AOP实现Java程序增强

    1.注解介绍 1.1注解的本质 Oracle官方对注解的定义为: Annotations, a form of metadata, provide data about a program that ...

  10. Asa's Chess Problem

    一.题目 给定一张 \(n\times n\) 的矩阵,每个点上面有黑棋或者是白棋,给定 \(\frac{n\times n}{2}\) 对可以交换的位置,每对位置一定在同一行 \(/\) 同一列.\ ...