SimpleDataFormat 非线程安全
目录
前言
正文
1.出现异常
2.解决方法1
3.解决方法2
总结
前言
SimpleDateFormat类是 Java 中处理日期和时间格式化和解析的类,但它并不是线程安全的。这意味着多个线程不能安全地共享一个SimpleDateFormat实例进行日期和时间的解析和格式化。当多个线程共享同一个SimpleDateFormat实例时,会因为SimpleDateFormat内部维护的日历字段(例如:Calendar对象)等的竞争条件而导致解析和格式化错误。
正文
类 SimpleDataFormat 的可以对日期进行解析与格式化,但在使用时如果不想使用 0 进行填充,比如 2000-01-02 只想转换成 2002-1-2 ,我们需要在代码上进行处理,示例代码如下。
package org.example.SimpleDataFormat;import java.text.ParseException;
import java.text.SimpleDateFormat;public class Run {public static void main(String[] args) throws ParseException {String dataString1 = "2000-1-1";String dataString2 = "2000-11-18";SimpleDateFormat format1 = new SimpleDateFormat("yyyy-M-d");SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd");//先按照日期模式将字符串解析成日期再格式化成时间字符串。System.out.println(format1.format(format1.parse(dataString1)));System.out.println(format2.format(format2.parse(dataString1)));System.out.println(format1.format(format1.parse(dataString2)));System.out.println(format2.format(format2.parse(dataString2)));}
}
打印结果如下:

但 SimpleDateFormat 在多线程环境中使用类容易造成数据转换及处理不准确,因为类 SimpleDateFormat 并不是线程安全的。
1.出现异常
本示例将展示使用类 SimpleDataFormat 在多线程环境中处理日期时得到错误结果,这也是在多线程环境中开发经常遇到的问题。
ackage org.example.SimpleDataFormat;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class formatError {static class MyThread extends Thread {private SimpleDateFormat sdf;private String dateString;public MyThread(SimpleDateFormat sdf, String dateString) {this.sdf = sdf;this.dateString = dateString;}@Overridepublic void run() {try {Date dateRef = sdf.parse(dateString);String newDataString = sdf.format(dateRef);if (!newDataString.equals(dateString)) {System.out.println("ThreadName=" + this.getName()+ "报错了 日期字符串:" + dateString + " 转换成的日期为:"+ newDataString);}} catch (ParseException e) {e.printStackTrace();}}}public static void main(String[] args) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String[] dateStringArray = new String[]{"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10",};MyThread[] threads = new MyThread[10];for (int i = 0; i < 10; i++) {threads[i] = new MyThread(sdf,dateStringArray[i]);}for (int i = 0; i < 10; i++) {threads[i].start();}}
}
运行结果如图:
从打印的结果来看,使用单例的类 SimpleDateFormat 在多线程环境中处理日期极易出现转换错误的情况。
甚至由于竞争导致解析逻辑的数字处理部分冲突,控制台照成了错误输出 。

2.解决方法1
第一种解决办法的原理是满足竞争,创建多个类 SimpleDateFormat 的实例。
package org.example.SimpleDataFormat;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class formatOK1 {static class DateTools{public static Date parse(String formatPattern, String dateString) throws ParseException {return new SimpleDateFormat(formatPattern).parse(dateString);}public static String format(String formatPattern, Date date) {return new SimpleDateFormat(formatPattern).format(date);}}static class MyThread extends Thread {private SimpleDateFormat sdf;private String dateString;public MyThread(SimpleDateFormat sdf, String dateString) {this.sdf = sdf;this.dateString = dateString;}@Overridepublic void run() {try {Date dateRef = DateTools.parse("yyyy-MM-dd",dateString);String newDataString = DateTools.format("yyyy-MM-dd",dateRef);if (!newDataString.equals(dateString)) {System.out.println("ThreadName=" + this.getName()+ "报错了 日期字符串:" + dateString + " 转换成的日期为:"+ newDataString);}} catch (ParseException e) {e.printStackTrace();}}}public static void main(String[] args) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String[] dateStringArray = new String[]{"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10",};MyThread[] threads = new MyThread[10];for (int i = 0; i < 10; i++) {threads[i] = new MyThread(sdf,dateStringArray[i]);}for (int i = 0; i < 10; i++) {threads[i].start();}}
}
运行结果如图:

控制台没有异常信息输出。
3.解决方法2
还有一种更简单的方法,那就是使用 ThreadLocal 包装SimpleDateFormat。ThreadLocal 可以为每个线程提供一个单独的 SimpleDateFormat 实例,能使线程绑定到指定对象。使用该类也可以解决多线程环境中类 SimpleDateFormat 处理日期时出现错误的问题。
package org.example.SimpleDataFormat;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class formatOK2 {static class DateTools {private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>();public static SimpleDateFormat getSimpleDateFormat(String datePattern) {SimpleDateFormat sdf = null;sdf = t1.get();if (sdf == null) {sdf = new SimpleDateFormat(datePattern);t1.set(sdf);}return sdf;}}static class MyThread extends Thread {private SimpleDateFormat sdf;private String dateString;public MyThread(SimpleDateFormat sdf, String dateString) {this.sdf = sdf;this.dateString = dateString;}@Overridepublic void run() {try {Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);String newDataString = DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef);if (!newDataString.equals(dateString)) {System.out.println("ThreadName=" + this.getName()+ "报错了 日期字符串:" + dateString + " 转换成的日期为:"+ newDataString);}} catch (ParseException e) {e.printStackTrace();}}}public static void main(String[] args) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String[] dateStringArray = new String[]{"2000-01-01","2000-01-02", "2000-01-03", "2000-01-04","2000-01-05", "2000-01-06", "2000-01-07","2000-01-08", "2000-01-09", "2000-01-10",};MyThread[] threads = new MyThread[10];for (int i = 0; i < 10; i++) {threads[i] = new MyThread(sdf, dateStringArray[i]);}for (int i = 0; i < 10; i++) {threads[i].start();}}
}
运行结果:

控制台没有异常信息输出,说明 ThreadLocal 解决了 SimpleDateFormat 非线程安全问题。
总结
加油!!!!
相关文章:
SimpleDataFormat 非线程安全
目录 前言 正文 1.出现异常 2.解决方法1 3.解决方法2 总结 前言 SimpleDateFormat 类是 Java 中处理日期和时间格式化和解析的类,但它并不是线程安全的。这意味着多个线程不能安全地共享一个 SimpleDateFormat 实例进行日期和时间的解析和格式化。当多个…...
SpringBoot : ch12 多模块配置YAML文件
前言 当您使用SpringBoot框架进行项目开发时,通常需要配置一些参数和属性。在实际开发中,可能需要将这些配置参数分成多个不同的YAML文件,并将它们组织到不同的模块中。这样可以方便管理和维护配置文件,并且可以避免配置文件的冲…...
TensorRT之LeNet5部署(onnx方式)
文章目录 前言LeNet-5部署1.ONNX文件导出2.TensorRT构建阶段(TensorRT模型文件)🧁创建Builder🍧创建Network🍭使用onnxparser构建网络🍬优化网络🍡序列化模型🍩释放资源 3.TensorRT运行时阶段(推理)&#x…...
Xilinx FPGA平台DDR3设计详解(二):DDR SDRAM组成与工作过程
本文主要介绍一下DDR SDRAM的基本组成以及工作过程,方便大家更好的理解和掌握DDR的控制与读写。 一、DDR SDRAM的基本组成 1、SDRAM的基本单元 SDRAM的基本单元是一个CMOS晶体管和一个电容组成的电路。 晶体管最上面的一端,称作栅极,通过…...
ios(swiftui) 属性包装器详解
目录 1. State 2. Binding 3. ObservedObject 和Published 4. StateObject 5. EnvironmentObject和Environment 6. AppStorage 在 SwiftUI 中,属性包装器用于增强和管理视图的状态,以及处理视图与数据模型之间的绑定和交互。下面是一些常见…...
【智能家居】面向对象编程OOP和设计模式(工厂模式)
面向对象编程 类和对象 面向对象编程和面向过程编程区别 设计模式 软件设计模式按类型分 工厂模式 面向对象编程 面向对象编程(Object-Oriented Programming,OOP)是一种程序设计范式,其中程序被组织成对象的集合,每…...
Docker安装Memcached+Python调用
简介:Memcached是一个通用的分布式内存缓存系统。它通常用于通过在RAM中缓存数据和对象来加速动态数据库驱动的网站,以减少必须读取外部数据源(如数据库或API)的次数。Memcached的API提供了一个分布在多台机器上的非常大的哈希表。…...
网页开发 HTML
目录 HTML概述 HTML结构 HTML标签语法 基本标签 标题标签 换行标签 段落标签 文本格式化标签 特殊符号 div和span标签 超链接标签 锚点 img标签 列表标签 表格标签 表单标签 HTML概述 HTML,即超文本标记语言(HyperText Markup Language …...
SHAP(五):使用 XGBoost 进行人口普查收入分类
SHAP(五):使用 XGBoost 进行人口普查收入分类 本笔记本演示了如何使用 XGBoost 预测个人年收入超过 5 万美元的概率。 它使用标准 UCI 成人收入数据集。 要下载此笔记本的副本,请访问 github。 XGBoost 等梯度增强机方法对于具有…...
LeetCode 8 字符串转整数
题目描述 字符串转换整数 (atoi) 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C 中的 atoi 函数)。 函数 myAtoi(string s) 的算法如下: 读入字符串并丢弃无用的前导空格检查下一…...
前缀和 LeetCode1423. 可获得的最大点数
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。 每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。 你的点数就是你拿到手中的所有卡牌的点数之和。 给你一个整数数组 cardPoi…...
探索意义的深度:自然语言处理中的语义相似性
一、说明 语义相似度,反应出计算机对相同内容,不同表达的识别能力。因而识别范围至少是个句子,最大范围就是文章,其研究方法有所区别。本文将按照目前高手的研究成绩,作为谈资介绍给诸位。 二、语义相似度简介 自然语言…...
WT2605-24SS高品质录音语音芯片:实时输出、不保存本地,引领音频技术新潮流
随着科技的快速发展,高品质音频技术成为了现代社会不可或缺的一部分。在这个追求高品质、高效率的时代,唯创知音推出的WT2605-24SS高品质录音芯片,以其独特的功能和卓越的性能,引领着音频技术的新潮流。 首先,WT2605-…...
Git 合并冲突解决步骤
Git 合并冲突解决步骤 1. 找到并打开冲突文件 定位到发生冲突的文件。可以通过 Git 的命令行输出找到这些文件。例如: pom.xmlsrc/main/java/com/zzm/config/SecurityConfig.javasrc/main/java/com/zzm/service/chat/UserConversationsServiceImpl.javasrc/main/…...
Windows核心编程 注册表
目录 注册表概述 打开关闭注册表 创建删除子健 查询写入删除键值 子健和键值的枚举 常用注册表操作 注册表概述 注册表是Windows操作系统、硬件设备以及客户应用程序得以正常运行和保存设置的核心"数据库",也可以说是一个非常巨大的树状分层结构的…...
【算法专题】二分查找
二分查找 二分查找1. 二分查找2. 在排序数组中查找元素的第一和最后一个位置3. 搜索插入位置4. x 的平方根5. 山脉数组的峰顶索引6. 寻找峰值7. 寻找旋转排序数组中的最小值8. 点名 二分查找 1. 二分查找 题目链接 -> Leetcode -704.二分查找 Leetcode -704.二分查找 题…...
中国消费电子行业发展趋势及消费者需求洞察|徐礼昭
一、引言 近年来,随着科技的飞速发展,消费电子行业面临着前所未有的挑战与机遇。本文将从行业发展趋势、消费者需求洞察以及企业数字化转型的方向和动作三个方面,对消费电子行业进行深入剖析。 二、消费电子行业发展趋势 5G技术的普及和应…...
UE学习C++(1)创建actor
创建新C类 在 虚幻编辑器 中,点击 文件(File) 下拉菜单,然后选择 新建C类...(New C Class...) 命令: 此时将显示 选择父类(Choose Parent Class) 菜单。可以选择要扩展的…...
【CTA认证】Android8实现android6以下的应用运行时也要申请权限
需求 CTA入网认证,要求低版本比如Android6以下的应用,运行时,也需要有运行时权限(Runtime Permission)功能,不能默认就取到权限,必须人工在设置中打开才可。 环境 Android 8 实现 frameworks 修改思路是所有APP都…...
gRPC Java、Go、PHP使用例子
文章目录 1、Protocol Buffers定义接口1.1、编写接口服务1.2、Protobuf基础数据类型 2、服务器端实现2.1、生成gRPC服务类2.2、Java服务器端实现 3、java、go、php客户端实现3.1、Java客户端实现3.2、Go客户端实现3.3、PHP客户端实现 本文例子是在Window平台测试,Ja…...
如何用Python在5分钟内自动解析简历关键信息?PyResParser终极指南
如何用Python在5分钟内自动解析简历关键信息?PyResParser终极指南 【免费下载链接】pyresparser A simple resume parser used for extracting information from resumes 项目地址: https://gitcode.com/gh_mirrors/py/pyresparser 在招聘高峰期,…...
如何彻底解决Windows系统DLL缺失问题:Visual C++运行库一键修复终极指南
如何彻底解决Windows系统DLL缺失问题:Visual C运行库一键修复终极指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过打开软件时突…...
ElevenLabs奥里亚文语音SDK集成终极 checklist:从Unicode 13.0字符兼容性到Odia Conjunct Glyph渲染异常修复
更多请点击: https://intelliparadigm.com 第一章:ElevenLabs奥里亚文语音SDK集成终极 checklist:从Unicode 13.0字符兼容性到Odia Conjunct Glyph渲染异常修复 Unicode 13.0 兼容性验证 ElevenLabs v4.2.1 SDK 默认支持 Unicode 13.0&…...
终极文档下载神器:30+平台一键免费保存,告别繁琐下载流程
终极文档下载神器:30平台一键免费保存,告别繁琐下载流程 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该…...
实验室小白避坑指南:在浪潮AiStation上从零部署PyTorch项目(含离线环境打包)
实验室科研实战:浪潮AiStation离线部署PyTorch全流程解析 当实验室服务器遭遇网络隔离与资源限制时,如何高效部署深度学习项目成为每个科研新手的必修课。本文将针对浪潮AiStation平台的特殊性,系统梳理从环境准备到代码运行的完整闭环&#…...
从CTF逆向到软件分析:用z3-solver自动化求解约束方程
1. 为什么我们需要z3-solver? 第一次参加CTF比赛时,我遇到一道逆向题,需要解一个包含30多个变量的方程组。当时我花了整整两天时间手工计算,最后还是没能解出来。赛后才知道,原来可以用z3-solver在几分钟内自动求解。这…...
Spring Boot安全脚手架:openclaw-security-starter核心架构与实战指南
1. 项目概述:一个面向开发者的安全脚手架最近在梳理团队内部的安全开发规范时,发现一个普遍痛点:每个新项目启动,安全相关的配置总是东拼西凑,从依赖扫描、密钥管理到API安全策略,都得重新来一遍࿰…...
巧用邮件合并批量生成带条形码的证件标签
1. 为什么需要批量生成带条形码的证件标签? 在日常办公中,我们经常会遇到需要批量制作证件标签的情况。比如学校图书馆要给新生办理借书证,公司要给新员工制作工牌,或者社区要给居民发放会员卡。传统的手工制作方式不仅效率低下&…...
深入TEA5767数据手册:51单片机I²C驱动FM收音模块的避坑指南与调试心得
深入解析TEA5767:51单片机驱动FM收音模块的实战技巧 在嵌入式开发领域,能够独立解读芯片手册并实现功能驱动是工程师的核心能力之一。TEA5767作为一款经典的FM收音芯片,因其低功耗、高集成度和简单的IC接口而广受欢迎。本文将从一个实际开发者…...
阿里云百炼 + OpenClaw 打造超强自动化 AI
前置准备 已安装并可正常打开 OpenClaw Windows 版本 OpenClaw 部署包获取:https://xiake.yun/api/download/package/14?promoCodeIVD643FDE29AOpenClaw 顶部 Gateway 状态显示为在线准备好可正常登录的阿里云账号可正常访问阿里云百炼控制台地址确认账号已开通百…...
