SimpleDataFormat 非线程安全

news2025/3/1 14:09:49

目录

前言 

正文 

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;
        }

        @Override
        public 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;
        }

        @Override
        public 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;
        }

        @Override
        public 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 非线程安全问题。  


总结

 加油!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1279131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第二次量子化

专栏目录: 高质量文章导航-持续更新中 前置复盘: 玻色子和费米子: 首先,我们希望把描述单粒子态的量子力学推广到全同多粒子体系。我们的做法是从单粒子态的希尔伯特空间(Hilbert Space)出发,构造全同多粒子态的态空间——福克空间(Fock Space),它实际上就是无穷个…

nodejs微信小程序+python+PHP药品招标采购系统的设计与实现-计算机毕业设计推荐MySQL

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

制作一个RISC-V的操作系统一-计算机系统漫游

文章目录 计算机的硬件组成两种架构程序的存储与执行程序语言的设计和进化一个mini计算机 编程语言的进化存储设备的层次结构操作系统 计算机的硬件组成 所有硬件由总线连接起来 两种架构 总线个数不同&#xff0c;Memory储存内容不同 程序的存储与执行 首先编译和链接某…

测试面经1130

深信服软件测试实习生面经 1. 自我介绍2. 深入的聊一下软件测试岗位主要是干什么的&#xff1f;是一个怎样的工作&#xff1f;他的职责定位&#xff1f;软件测试需要哪些知识技能&#xff08;软件测试是做什么的&#xff1f;&#xff09;3. 如果开发了一个系统&#xff0c;没有…

计算机毕业设计 基于Web的铁路订票管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

解读Java虚拟机垃圾回收器:探究经典算法背后的奥秘

目录 一、GC分类与性能指标 &#xff08;一&#xff09;垃圾回收器分类 &#xff08;二&#xff09;性能指标 &#xff08;三&#xff09;不可能三角 二、不同的垃圾回收器概述 三、Serial回收器&#xff1a;串行回收 四、ParNew回收器&#xff1a;并行回收 五、Parall…

可视化数据库管理客户端:Adminer

简介&#xff1a;Adminer&#xff08;前身为phpMinAdmin&#xff09;是一个用PHP编写的功能齐全的数据库管理工具。与phpMyAdmin相反&#xff0c;它由一个可以部署到目标服务器的文件组成。Adminer可用于MySQL、PostgreSQL、SQLite、MS SQL、Oracle、Firebird、SimpleDB、Elast…

水果编曲软件fl studio手机版下载

fl studio mobile手机版中文名水果编曲软件&#xff0c;它是一款非常不错的音乐编曲软件&#xff0c;凭借简单易上手的操作方式&#xff0c;强悍且实用的功能&#xff0c;深受到了音乐创作者的喜爱&#xff0c;不仅仅提供了广阔的音乐创作空间&#xff0c;可以让用户对舞曲、轻…

巧用MACD精准抄底和逃顶

一、认识MACD MACD又称平滑异同移动平均线&#xff0c;是由美国投资家杰拉尔德阿佩尔在 20 世纪 70 年代末提出的。 MACD 指标的设计基于MA均线原理&#xff0c;是对收盘价进行平滑处理&#xff08;求出加权平均值&#xff09;后的一种趋向类指标。它是股票交易中一种常见的技术…

CGAL的三维曲面细分方法

1、介绍 细分方法是从任意多边形网格生成平滑曲面的简单而强大的方法。与基于样条曲面的方法&#xff08;如NURBS&#xff09;或其他基于数字的建模技术不同&#xff0c;细分方法的使用者不需要掌握细分方法的数学知识。几何的直观性足以控制细分方法。 Subdivision_method_3适…

【U8+】用友U8删除固定资产卡片,提示:当前卡片不是本月录入的卡片,不能删除。

【问题描述】 用友U8软件&#xff0c;参照已有账套新建账套的时候&#xff0c;选择结转期初余额。 例如&#xff1a;参照已有账套的2022年新建2023年的账套。 结转期初的时候勾选了固定资产模块&#xff0c; 建立成功后登录23年新的账套后&#xff0c;删除固定资产卡片&#xf…

CSS 滚动捕获 scroll-margin

CSS滚动捕获 scroll-margin 非滚动捕获容器语法兼容性 CSS滚动捕获 scroll-margin 设置元素的滚动外边距 非滚动捕获容器 之前在 scroll-padding 中说过如何用 scroll-padding 避免锚点定位时元素贴着容器边缘的问题, 现在我们尝试用 scroll-margin 解决 <body><ma…

electerm下载和安装

electerm下载和安装 一、概述 electerm 是一款免费开源、基于electron/ssh2/node-pty/xterm/antd/ subx等libs的终端/ssh/sftp客户端(linux, mac, win)。 而且个人觉得electerm界面更好看一些&#xff0c;操作都是类似的。 二、下载安装 下载地址&#xff1a;https://elec…

opencv知识库:基于cv2.flip()函数对图像进行随机翻转(水平/垂直)

需求场景 欲对RGB格式的lena图像进行随机翻转&#xff0c;要求这些图像不翻转、水平翻转、垂直翻转的概率都为1/3。 功能代码 import cv2 import random# 读取并展示图像 img cv2.imread("lena.jpg") cv2.imshow(lena, img) cv2.waitKey(0)for i in range(6): #…

react之ReactRouter的使用

react之ReactRouter的使用 一、环境搭建二、抽象路由模块三、路由导航3.1 声明式导航3.2 编程式导航 四、导航传参4.1 searchParams 传参4.2 params 传参 五 、嵌套路由配置六、默认二级路由七、404页面配置八、俩种路由模式 一、环境搭建 1.创建项目安装依赖 npx create-rea…

【每日OJ —— 226. 翻转二叉树】

每日OJ —— 226. 翻转二叉树 1.题目&#xff1a;226. 翻转二叉树2.解法2.1.算法讲解2.2.代码实现2.3.代码提交通过展示 1.题目&#xff1a;226. 翻转二叉树 2.解法 2.1.算法讲解 我们从根节点开始&#xff0c;递归地对树进行遍历&#xff0c;并从叶子节点先开始翻转。如果当前…

Spring是怎么解决循环依赖的?

什么是循环依赖 循坏依赖就是字面意思&#xff0c;A 依赖了 B&#xff0c;B 同时也依赖了 A。 如下所示 Component public class A {// A中注入了BAutowiredprivate B b; }Component public class B {// B中也注入了AAutowiredprivate A a;又或者是下面这种 // 自己依赖自己…

Zabbix监控接收SNMPTrap消息与SNMPTT结合

一.SNMP 协议 1.协议介绍 snmp 协议是日常使用的较多的一种协议&#xff0c;绝大多数网络设备/存储等都支持 snmp 协议&#xff0c;通过此协议可以实现设备状态的监控及管理。 2.主要组成 SNMP 协议包括以下三个部分: SNMP Agent&#xff1a;负责处理 snmp 请求&#xff0c…

Python实战:批量加密Excel文件指南

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python实战&#xff1a;批量加密Excel文件指南&#xff0c;全文3800字&#xff0c;阅读大约10分钟。 在日常工作中&#xff0c;保护敏感数据是至关重要的。本文将引导你通过…

ARP安全综合功能示例

ARP安全简介 定义 ARP&#xff08;Address Resolution Protocol&#xff09;安全是针对ARP攻击的一种安全特性&#xff0c;它通过一系列对ARP表项学习和ARP报文处理的限制、检查等措施来保证网络设备的安全性。ARP安全特性不仅能够防范针对ARP协议的攻击&#xff0c;还可以防…