求求你别用SimpleDateFormat了!
前言
啊哈哈,标题写的比较随意了,其实呢最近在各种面试以及博客中,SimpleDateFormat出镜率确实是比较高了,为什么?其实聪明的你们肯定知道,那必须是有坑呗,是的,那我们就以案例来分析一下到底会有那些坑,或者还有没有其他更优的替代方案呢?
正文
首先我们来看一下可能会出现在DateUtils中的写法:
private static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Date formatDate(String date) throws ParseException {
return dayFormat.parse(date);
}
当我们在单线程的程序中调用 formatDate(date) ,此时并不会出现任何问题(如果这也出问题那还玩什么...) ,然而当我们的程序在多线程并发执行调用这个方法的时候。
ExecuterService es = ExecuterService.newFixedThreadPool(50);
for( ... ){
es.execute( () -> {
System.out.println(parse("2018-11-11 10:35:20"));
})
}
此时你会发现打印出来的时间有些是错误,程序甚至会抛出异常NumberFormatException??为什么会出现这种情况呢?我们可以直接查看SimpleDateFormat.parse() 方法的源码一探究竟。
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++\]; }
从源码可以看到,在多线程的环境中,执行到第五行 calendar进行操作的时候,后面的线程有可能会覆盖上一个线程设置好的值,此时就导致前面线程执行的结果被覆盖而返回了一个错误的值。
那我们该如何避免这个坑呢?
1、使用ThreadLocal,每个线程中返回各自的实例,避免了多线程环境中共用同一个实例而导致的问题。
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<>();
public static Date formatDate(String date) throws ParseException {
SimpleDateFormat dayFormat = getSimpleDateFormat();
return dayFormat.parse(date);
}
private static SimpleDateFormat getSimpleDateFormat() {
SimpleDateFormat simpleDateFormat = simpleDateFormatThreadLocal.get();
if (simpleDateFormat == null){
simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
simpleDateFormatThreadLocal.set(simpleDateFormat);
}
return simpleDateFormat;
}
需要注意一点的是,ThreadLocal的使用过程中也是有小坑需要注意的,大家可以参考一下其他的资料,以后可以抽空聊聊这个话题。
2、推荐升级到JDK8+,使用LocalDateTime,LocalDate,LocalTime来代替,具体的用法请自行参考API,当然JDK8所带来的Lambda,Stream等特性也是值得一试的。
3、使用三方包,推荐Joda-Time,对于日期的增减操作也是相当便捷。
github:https://github.com/JodaOrg/joda-time
求求你别用SimpleDateFormat了!的更多相关文章
- SimpleDateFormat使用详解——日期、字符串应用
public class SimpleDateFormat extends DateFormat SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (d ...
- SimpleDateFormat转换时间格式
SimpleDateFormat有两个常用的方法parse和format 其中SimpleDateFormat在创建时有一下集中格式可以选择 SimpleDateFormat sdf = new Si ...
- DateUtil(SimpleDateFormat)
import java.util.Calendar; import java.util.Date; import java.text.SimpleDateFormat; public class Da ...
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
java日期格式大全 format SimpleDateFormat(转) SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH ...
- java 中的SimpleDateFormat、Date函数以及字符串和Date类型互转
SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本).解析(文本 -> 日期)和规范化. SimpleDateFor ...
- java日期处理SimpleDateFormat等
1.mysql数据库中有这样一个表: mysql> select * from test_table;+----------+---------------------+| username | ...
- SimpleDateFormat的应用
import java.text.SimpleDateFormat;import java.util.Date;public class Main { public static void ma ...
- 使用 Date 和 SimpleDateFormat 类表示时间、Calendar类和Math类
一. Date 和 SimpleDateFormat类表示时间 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Date 类.这个类最主要的作用就是获取当 ...
- Java SimpleDateFormat使用
SimpleDateFormat 是一个格式化日期的具体类. 它允许格式化 (date -> text) 和标准化. SimpleDateFormat 允许以为日期-时间格式化选择任何用户指定的 ...
随机推荐
- op.go
package } ) : : : ,: ,: : : ,: ,: : : ,: ,: ;; ] )} } minutes when there is no incoming events. // P ...
- 一类SG函数递推性质的深入分析——2018ACM陕西邀请赛H题
题目描述 定义一种有根二叉树\(T(n)\)如下: (1)\(T(1)\)是一条长度为\(p\)的链: (2)\(T(2)\)是一条长度为\(q\)的链: (3)\(T(i)\)是一棵二叉树,它的左子 ...
- bzoj 3167 SAO
树dp 定义f[i][j]为i在其已合并子树内排名为j的方案数 O(n2)进行子树合并 转移时枚举他在已合并子树中的排名j和新合并子树中的排名k+1 当他比他儿子大的时候$f[x][j+k]=f[x] ...
- linux 挂载共享文件夹
1.背景 通常会有这样的场景,开发人员在Windows编写代码,然后放在linux环境编译,我们通过mount命令就可以实现将代码直接挂到linux环境上去,使Windows上的共享文件夹就像linu ...
- SpringCloud学习系列之六 ----- 路由网关Zuul基础使用教程
前言 在上篇中介绍了SpringCloud Config的完美使用版本,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloud Finchley版)中的路由网关 ...
- python基于selenium实现自动删除qq空间留言板
py大法好,让你解放双手. 脚本环境 python环境,selenium库,Chrome webdriver驱动等. 源码 # coding=utf-8 import datetime import ...
- 跟我一起学opencv 第四课之图像的基本操作
1.图像是由像素组成的,所以修改了像素就可以实现图像的改变. 2先看灰度图像(单通道): *****2.获取灰度图像的像素值使用: int gray = gray_src.at<uchar&g ...
- .net core 注入中的三种模式:Singleton、Scoped 和 Transient
从上篇内容不如题的文章<.net core 并发下的线程安全问题>扩展认识.net core注入中的三种模式:Singleton.Scoped 和 Transient 我们都知道在 Sta ...
- 一个实时收集MySql变更记录的组件CanalSharp.AspNetCore
一.关于CanalSharp CanalSharp 是阿里巴巴开源项目 Canal 的 .NET 客户端.为 .NET 开发者提供一个更友好的使用 Canal 的方式.Canal 是mysql数据库b ...
- 如何在ASP.NET Core中使用Azure Service Bus Queue
原文:USING AZURE SERVICE BUS QUEUES WITH ASP.NET CORE SERVICES 作者:damienbod 译文:如何在ASP.NET Core中使用Azure ...