当前位置: 首页 > news >正文

深入理解高并发编程 - SimpleDateFormat 类的线程安全问题

1、重现与解决

1.1、重现

import java.text.SimpleDateFormat;
import java.util.Date;public class UnsafeSimpleDateFormatExample {public static void main(String[] args) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Runnable task = () -> {for (int i = 0; i < 5; i++) {String formattedDate = sdf.format(new Date());System.out.println(Thread.currentThread().getName() + ": Formatted Date: " + formattedDate);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}};Thread thread1 = new Thread(task, "Thread-1");Thread thread2 = new Thread(task, "Thread-2");thread1.start();thread2.start();}
}

在这个示例中,创建了两个线程,它们共享同一个 SimpleDateFormat 实例来格式化当前日期和时间。由于 SimpleDateFormat 内部状态不是线程安全的,可能会观察到以下问题:

输出的日期格式可能交错出现,因为两个线程在竞争访问共享的 SimpleDateFormat 实例,导致格式化结果混乱。
可能会抛出异常,如 ArrayIndexOutOfBoundsException 或 StringIndexOutOfBoundsException,这是因为线程竞争导致 SimpleDateFormat 内部状态不一致。

这个示例中,每个线程都会尝试格式化当前日期和时间,并在输出时稍微延迟一段时间。由于没有对 SimpleDateFormat 进行线程保护,两个线程可能会相互干扰,导致输出的格式化结果不符合预期,甚至引发异常。

要避免这个问题,可以使用线程局部变量(ThreadLocal)来确保每个线程都有自己的 SimpleDateFormat 实例,或者使用线程安全的替代类,如 Java 8 中的 DateTimeFormatter。

1.2、使用线程局部变量(ThreadLocal)

package com.lfsun.main.basic.myjuc.depthstudy.threadsafequestion;import java.text.SimpleDateFormat;
import java.util.Date;public class ThreadLocalSimpleDateFormatExample {private static ThreadLocal<SimpleDateFormat> threadLocalSdf = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));public static void main(String[] args) {Runnable task = () -> {SimpleDateFormat sdf = threadLocalSdf.get();for (int i = 0; i < 5; i++) {String formattedDate = sdf.format(new Date());System.out.println(Thread.currentThread().getName() + ": Formatted Date: " + formattedDate);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}};Thread thread1 = new Thread(task, "Thread-1");Thread thread2 = new Thread(task, "Thread-2");thread1.start();thread2.start();}
}

使用 ThreadLocal 的主要目的是为每个线程提供一个独立的实例,从而避免共享资源的线程安全问题。不需要额外的同步机制,除非在某些特定情况下需要跨线程共享某些资源。

1.3、使用线程安全的替代类,如 Java 8 中的 DateTimeFormatter。

package com.lfsun.main.basic.myjuc.depthstudy.threadsafequestion;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;public class DateTimeFormatterExample {public static void main(String[] args) {DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");Runnable task = () -> {for (int i = 0; i < 5; i++) {String formattedDate = dtf.format(LocalDateTime.now());System.out.println(Thread.currentThread().getName() + ": Formatted Date: " + formattedDate);try {Thread.sleep(100); // 模拟一些处理时间} catch (InterruptedException e) {e.printStackTrace();}}};// 创建和启动多个线程以演示线程安全Thread thread1 = new Thread(task, "Thread-1");Thread thread2 = new Thread(task, "Thread-2");thread1.start();thread2.start();}
}

1.4、Joda-Time

在 Java 8 引入新的 java.time 包之前,Joda-Time被广泛用于处理日期和时间。Joda-Time 提供了一组线程安全的日期和时间类,可以帮助解决 SimpleDateFormat 在多线程环境中的线程安全问题。

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;public class JodaTimeExample {public static void main(String[] args) {DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");Runnable task = () -> {for (int i = 0; i < 5; i++) {String formattedDate = dtf.print(DateTime.now());System.out.println(Thread.currentThread().getName() + ": Formatted Date: " + formattedDate);try {Thread.sleep(100); // 模拟一些处理时间} catch (InterruptedException e) {e.printStackTrace();}}};// 创建和启动多个线程以演示线程安全Thread thread1 = new Thread(task, "Thread-1");Thread thread2 = new Thread(task, "Thread-2");thread1.start();thread2.start();}
}

在这个示例中,使用了 Joda-Time 库的 DateTime 类和 DateTimeFormatter 来格式化和解析日期。Joda-Time 提供的日期和时间类都是线程安全的,因此可以在多线程环境中共享使用,无需担心线程安全问题。

需要注意的是,从 Java 8 开始,Java 标准库中引入了新的日期和时间 API(java.time 包),其中包含了线程安全的日期和时间类。所以,在 Java 8 及以后的版本中,也可以使用这个新的日期和时间 API 来避免 SimpleDateFormat 的线程安全问题。

2、SimpleDateFormat 类为何不是线程安全的?

SimpleDateFormat 类不是线程安全的主要原因在于其内部状态以及对共享资源的操作可能会导致竞争条件和数据不一致。以下是一些导致 SimpleDateFormat 类不是线程安全的原因:

内部状态共享: SimpleDateFormat 内部维护了日期格式化模式(pattern)、时区信息、语言环境等状态。多个线程同时使用同一个 SimpleDateFormat 实例时,它们会访问和修改相同的内部状态,可能导致数据混乱。线程间竞争: 在多线程环境中,多个线程同时对同一个 SimpleDateFormat 实例进行格式化或解析操作时,它们会竞争修改内部状态,导致输出结果混乱。非原子性操作: SimpleDateFormat 内部的状态修改操作可能不是原子性的,这意味着多个线程在同时修改状态时可能会产生竞争条件,导致数据错误或异常。共享的 Calendar 实例: SimpleDateFormat 内部使用了共享的 Calendar 实例,可能会在多线程环境中产生问题,因为 Calendar 本身也不是线程安全的。

由于上述原因,如果多个线程同时使用同一个 SimpleDateFormat 实例进行格式化和解析操作,就有可能导致线程不安全的问题,从而产生意外的结果、异常或混乱的输出。

相关文章:

深入理解高并发编程 - SimpleDateFormat 类的线程安全问题

1、重现与解决 1.1、重现 import java.text.SimpleDateFormat; import java.util.Date;public class UnsafeSimpleDateFormatExample {public static void main(String[] args) {SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Runnable task…...

接口幂等性实现方式

优质博文&#xff1a;IT-BLOG-CN 幂等 操作的特点是一次和多次请求某一个资源对于资源本身应该具有同样的结果&#xff08;网络超时等问题除外&#xff09;。幂等函数或幂等方法是指可以使用相同参数重复执行&#xff0c;并能获得相同结果的函数。这些函数不会影响系统状态&am…...

redis高可用之持久化

目录 一、Redis 高可用的相关知识 1&#xff09;什么是高可用 2&#xff09;Redis的高可用技术 3&#xff09;持久化的功能 4&#xff09;redis持久化的方式 二、RDB持久化 1&#xff09;RDB持久化的触发方式 &#xff08;1&#xff09;手动触发 &#xff08;2&…...

Cocos Creator 3.8 后期效果 Shader 编写(2/2) 进阶篇

前言 在上一篇文章中&#xff0c;麒麟子给大家分享了如何在 Cocos Creator 3.8 中的自定义管线中&#xff0c;添加属于自己的后期效果 Shader。 但基于 BlitScreen 的方案&#xff0c;我们只能编写最简单后效 Shader&#xff0c;如果我们想要支持更多复杂的 Shader&#xff0c…...

【JS自用模板】自动点击选课的操作模板

以激动点击课程为案例复习一下基本前端&#xff0c;容易涉及的问题包括如何提取object类的数字&#xff0c;setTimeout为什么不起作用&#xff1f; 具体思路是&#xff0c;此处会立刻选中符合条件的页面元素打开&#xff0c;然后1小时后会刷新页面&#xff0c;相应地播放页面也…...

TENNECO EDI 项目——X12与XML之间的转换

近期为了帮助广大用户更好地使用 EDI 系统&#xff0c;我们根据以往的项目实施经验&#xff0c;将成熟的 EDI 项目进行开源。用户安装好知行之桥EDI系统之后&#xff0c;只需要下载我们整理好的示例代码&#xff0c;并放置在知行之桥指定的工作区中&#xff0c;即可开始使用。 …...

C++项目:在线五子棋对战(网页版)

项目介绍 本项⽬主要实现⼀个⽹⻚版的五⼦棋对战游戏&#xff0c;其主要⽀持以下核⼼功能&#xff1a; • 用户管理:实现用户注册&#xff0c;用户登录、获取用户信息、用户天梯分数记录、用户比赛场次记录等。 • 匹配对战:实现两个玩家在网页端根据天梯分数匹配游戏对⼿&…...

flutter遇到的小问题记录

flutter-getx的Get.bottomSheet组件改变高度 Get.bottomSheet( isScrollControlled: true,) isScrollControlled: true 就是控制高度 (无语) 截取视频第一针 返回的是本地url 或者Uint8List的数据 String? videoStr await VideoThumbnail.thumbnailFile(video: videoPath,…...

Golang bitset 基本使用

安装&#xff1a; go get github.com/bits-and-blooms/bitset下面代码把fmtx换成fmt就行 //------------基本操作------------//构建一个64bit长度的bitsetb : bitset.New(64)//放入一个数b.Set(10)fmtx.Println("add-10&#xff1a;", b.DumpAsBits()) // 0000000…...

sql 分组讨论,二级分组(非2个字段分组),使用 窗口函数和普通分组实现

1. 二级分组需求 先按照一个字段分组&#xff0c;在按照 第二个字段分组。之后&#xff0c;如果 这个 二级分组中的数据&#xff0c;是 > 1条的。就筛选出来。 比如&#xff1a; 先按照 站点分组&#xff0c;再按照 设备分组&#xff0c; 即&#xff1a;如果站点上配置了…...

业务中如何过滤敏感词

在我们访问网站的时候&#xff0c;如果发现我们发布的内容有色情暴力的东西等等&#xff0c;会屏蔽掉&#xff0c;这种行为就是过滤敏感词。 从技术层面实现起来&#xff0c;其实比较简单&#xff0c;因为我们输入的内容就是一个大型的字符串&#xff0c;我们要调用某些api来判…...

用服务器搭建网站需要做什么

网站建设是一个广义的术语&#xff0c;涵盖了许多不同的技能和学科中所使用的生产和维护的网站。不同领域的网页设计&#xff0c;网页图形设计&#xff0c;界面设计&#xff0c;创作&#xff0c;其中包括标准化的代码和专有软件&#xff0c;用户体验设计和搜索引擎优化。许多人…...

clickhouse 删除操作

OLAP 数据库设计的宗旨在于分析适合一次插入多次查询的业务场景&#xff0c;市面上成熟的 AP 数据库在更新和删除操作上支持的均不是很好&#xff0c;当然 clickhouse 也不例外。但是不友好不代表不支持&#xff0c;本文主要介绍在 clickhouse 中如何实现数据的删除&#xff0c…...

C 语言中,「.」与「->」有什么区别?

使用“.”的话&#xff0c;只需要声明一个结构体。格式是结构体类型名结构体名。然后通过结构体名加上“.”再加上域名&#xff0c;就可以引用结构体的域了。因为结构体的内存是自动分配的&#xff0c;就像使用int a;一样。而使用“->”的话&#xff0c;需要声明一个结构体的…...

github pages 用法详解 发布自己的网站

github pages 基础用法 URL 规则 假设你的 github 帐号为 mygithub&#xff0c;需要发布的仓库名为 myrepo&#xff0c;那么 pages 的 URL 为&#xff1a; https://mygithub.github.io/myrepo 添加内容 用任意编辑器写好&#xff08;或者生成&#xff09;标准的网页内容&a…...

坤简炫酷的JQuery轮播图插件

介绍&#xff1a; 找到了一个炫酷的JQuery轮播图插件&#xff0c;只需要配置三四行代码就可以实现很多二维三维炫酷的切换效果。 视频效果及教程&#xff1a; https://www.bilibili.com/video/BV1Fu4y1d776/ 代码&#xff1a; https://github.com/w-x-x-w/AwesomeWeb 使用…...

C# 条件编译

C# 条件编译 C# 条件编译&#xff1a;根据不同的需求&#xff0c;编译生成不同的程序版本&#xff0c;条件编译是一种编译预处理命令&#xff0c;它是在编译代码之前对源代码进行处理。它可以根据条件&#xff0c;决定是否编译某段代码 条件编译的三种形式&#xff1a; 第一种…...

IntelliJ IDEA如何重新弹出git身份验证窗口

1、点击File菜单—>点击Settings—>点击Appearance & Behavior—>点击System Settings—>点击Passwords—>选中Do not save, forget passwords after restart—>点击Apply—>点击OK&#xff0c;如下所示&#xff1a; 2、重启IntelliJ IDEA—>通过g…...

【雕爷学编程】Arduino动手做(200)---WS2812B幻彩LED灯带4

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…...

【雕爷学编程】Arduino动手做(201)---DFRobot 行空板03

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...