当前位置: 首页 > 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…...

一款基于 .NET 开源、跨平台应用程序自动升级组件犊

基础示例&#xff1a;单工作表 Excel 转 TXT 以下是将一个 Excel 文件中的第一个工作表转换为 TXT 的完整步骤&#xff1a; 1. 加载并读取Excel文件 from spire.xls import * from spire.xls.common import * workbook Workbook() workbook.LoadFromFile("示例.xlsx"…...

告别 Notion AI 付费:利用 Gemini Client 自建最强笔记助手

前言 Notion作为现在最流行的笔记工具之一&#xff0c;其功能完整和页面美观而广受好评&#xff0c;但是它的ai功能是要钱的&#xff01;每月10美金&#xff01;这对笔者来说是不太能接受的&#xff0c;正巧最近有了gemini的会员并下载安装了cli&#xff0c;再加上最近酷爱逛魔…...

Alibi分布式计算指南:如何用Ray加速大规模模型解释

Alibi分布式计算指南&#xff1a;如何用Ray加速大规模模型解释 【免费下载链接】alibi Algorithms for explaining machine learning models 项目地址: https://gitcode.com/gh_mirrors/al/alibi 在处理大规模机器学习模型解释时&#xff0c;单机计算往往面临性能瓶颈。…...

通达信DLL插件实战:5分钟搞定热点板块成份股自动筛选(附股池模板)

通达信DLL插件高阶应用&#xff1a;热点板块成份股智能筛选全攻略 在瞬息万变的证券市场中&#xff0c;能否快速捕捉热点板块的轮动机会&#xff0c;往往决定了投资者的收益水平。传统手动筛选方式不仅效率低下&#xff0c;还容易错过最佳买卖时机。本文将深入解析如何利用通达…...

告别手动搬运:利用Gitee镜像功能实现GitHub仓库的自动同步

1. 为什么需要自动化同步GitHub和Gitee仓库 作为一个经常在GitHub和Gitee双平台托管代码的开发者&#xff0c;我深刻理解手动同步的痛苦。每次在GitHub上提交代码后&#xff0c;都要记得去Gitee手动更新&#xff0c;稍不留神就会忘记&#xff0c;导致两个平台的代码版本不一致。…...

GD32F103C8T6上跑FreeRTOS:保姆级移植教程,从源码下载到LED闪烁测试

GD32F103C8T6移植FreeRTOS实战指南&#xff1a;从零构建实时操作系统 第一次拿到GD32开发板时&#xff0c;我盯着这块"国产STM32"看了半天——引脚兼容、外设相似&#xff0c;但真要把成熟的FreeRTOS移植上去&#xff0c;还是遇到了不少坑。本文将用最接地气的方式&a…...

C#联合halcon开发框架源码。 拖拽式编程,无halcon基础也能上手,匹配,测量,条码识...

C#联合halcon开发框架源码。 拖拽式编程,无halcon基础也能上手&#xff0c;匹配&#xff0c;测量&#xff0c;条码识别&#xff0c;ocr,定位引导&#xff0c;对位等&#xff0c;支持plc通讯&#xff0c;集成主流相机sdk,系统集成. 最近在工业视觉项目里折腾Halcon的时候&#x…...

CMIP6实战指南:AI驱动的降尺度技术与区域气候影响深度解析

1. CMIP6与AI降尺度技术入门指南 当我们需要研究某个城市未来50年的气温变化时&#xff0c;全球气候模型&#xff08;GCM&#xff09;给出的数据往往像一张模糊的低像素照片——你能看出大概轮廓&#xff0c;但看不清细节。这就是CMIP6数据面临的典型问题&#xff1a;它的空间分…...

FLUX.2-klein-base-9b-nvfp4系统资源监控与优化:保障稳定运行

FLUX.2-klein-base-9b-nvfp4系统资源监控与优化&#xff1a;保障稳定运行 最近在星图GPU平台上部署了FLUX.2-klein-base-9b-nvfp4模型&#xff0c;跑起来效果确实不错。但用了一段时间后&#xff0c;我发现一个问题&#xff1a;模型服务偶尔会变慢&#xff0c;甚至卡住不动。一…...

STIX Two字体:解决学术文档跨平台符号显示问题的专业方案

STIX Two字体&#xff1a;解决学术文档跨平台符号显示问题的专业方案 【免费下载链接】stixfonts OpenType Unicode fonts for Scientific, Technical, and Mathematical texts 项目地址: https://gitcode.com/gh_mirrors/st/stixfonts 你是否曾遇到过这样的困扰&#x…...