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

        @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.mfbz.cn/a/213420.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaScript手撕代码】函数柯里化

函数柯里化 上面的api用的很多&#xff0c;所以都知道是干嘛的使用场景是什么&#xff0c;柯里化用得并不多&#xff0c;所以想手撕之前还是先了解一下它的意义以及用处 什么是柯里化 柯里化Currying又称部分求值&#xff0c;是高阶函数的一种&#xff0c;通常只需要把一部分…

【5G PHY】5G NR 如何计算资源块的数量?

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

【像素画板】游戏地图编辑器-uniapp项目开发流程详解

嘿&#xff0c;用过像素画板没有哦&#xff0c;相信喜欢绘画的小朋友会对它感兴趣呢&#xff0c;用来绘制像素画非常好看&#xff0c;有没有发现&#xff0c;它是可以用来绘制游戏地图的&#xff0c;是不是很好奇&#xff0c;来一起看看吧。 像素画板&#xff0c;也叫像素画的绘…

C++基础 -34- 输入输出运算符重载

输出运算符重载格式 ostream & operator<<(ostream &out,person a) {cout << a.a << endl;return out; }举例输出运算符重载 #include "iostream"using namespace std;class person {public:person(int a):a(a){}int a; };ostream &…

Go 语言中的反射机制

欢迎大家到我的博客浏览&#xff0c;更好的阅读体验请点击 反射 | YinKais Blog 反射在大多数的应用和服务中并不常见&#xff0c;但是很多框架都依赖 Go 语言的反射机制简化代码。<!--more-->因为 Go 语言的语法元素很少、设计简单&#xff0c;所以它没有特别强的表达能…

51. N 皇后

题目介绍 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案…

一文讲透Python函数的创建和调用

1.Python提供了函数作为完成某项工作的标准化代码块 Python本质上是一种编程语言&#xff0c;通过编写运行代码的方式实现工作目标。读者可以想象&#xff0c;如果针对机器学习或数据统计分析的每种方法或统计量计算都要用户自行编写代码&#xff0c;那么显然在很多情况下是无…

一款充电桩解决方案设计

一、基本的概述 项目由IP6536提供两路5V 1.5A 的USB充电口&#xff0c;IP6505提供一路最大24W的USB快充口支持QC3.0 / DCP / QC2.0 / MTK PE1.1 / PE2.0 / FCP / SCP / AFC / SFCP的快充协议&#xff0c;电池充电由type-C输入经过IP2326输出最高15W快充对电池进行充电&#xf…

VSCode 中将头文件和头文件函数分离,编译主函数跳出 undefined reference to 的问题解决

VSCode 编写 C &#xff08;.h&#xff0c;.cpp 文件分离&#xff09;代码&#xff0c;编写完成后&#xff0c;编译遇到了编译错误 undefined reference to xxx。 开始还以为使用了 -stdc20 而不能使用 #include “xxx.h" 方式头文件&#xff0c;但仔细一想虽然引入了 im…

18487.1 - 2015 电动汽车充电系统标准 第1部分 关键点梳理

一、部分知识介绍 1、连接方式 使用电缆和连接器将电动汽车接入电网&#xff08;电源&#xff09;的方法。 1.1、连接方式A 1.2、连接方式B 1.3、连接方式C 2、电动汽车控电设备 2.1、按照输出电压分类 1&#xff09;交流 单相 220V&#xff0c;三相 380V. 2&#xff09…

随心玩玩(十)git

写在前面&#xff1a;研究生一年多了&#xff0c;一直浑浑噩噩的&#xff0c;在深度学习的泥潭挣扎了好久&#xff0c;终于走出了精神内耗的泥潭…好久没有写博客了&#xff0c;决定重新捡起来…记录一下学习吧~ 之前写了一篇git的博客&#xff0c;【github 从0开始的基本操作…

LLM大语言模型(一):ChatGLM3-6B试用

前言 LLM大语言模型工程化&#xff0c;在本地搭建一套开源的LLM&#xff0c;方便后续的Agent等特性的研究。 本机环境 CPU&#xff1a;AMD Ryzen 5 3600X 6-Core Processor Mem&#xff1a;32GB GPU&#xff1a;RTX 4060Ti 16G ChatGLM3代码库下载 # 下载代码库 ​git c…

分类预测 | Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量输入数据分类预测

分类预测 | Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量输入数据分类预测 目录 分类预测 | Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量输入数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量…

搭建若依框架完成医疗项目 ——业务流程及页面展示

目录 一、搭建若依项目 1.1 快速了解 1.1.1 技术选型 1.1.2 内置功能 1.2 环境部署 二、医疗项目业务 2.1 门诊模块 2.2 住院模块 2.3 药房药库 2.4 表设计 三、项目展示 3.1 项目背景 3.2 门诊功能模块 3.2.1 患者档案 3.2.2 门诊卡信息 ​编辑 3.2.3 患者…

【文末送书】人工智能背景下的C++编程方向

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

Nginx转发内网Flv视频流

1、环境说明 Docker Nginx&#xff1a;1.21.5 实现Nginx ssl转发内网flv视频流 2、配置nginx.conf http {upstream live {server 10.10.10.10:8300;keepalive 64;}map $http_upgrade $connection_upgrade {default upgrade; close;}server {listen 80;listen 443…

echarts实现全国及各省市地图

echarts实现全国及各省市地图&#xff08;内附地图json文件&#xff09; 去阿里云就可以获取&#xff1a;[阿里云地理]&#xff1a;http://datav.aliyun.com/portal/school/atlas/area_selector#&lat31.769817845138945&lng104.29901249999999&zoom4(http://datav…

【自然语言处理】【大模型】VeRA:可调参数比LoRA小10倍的低秩微调方法

VeRA&#xff1a;可调参数比LoRA小10倍的低秩微调方法 《VeRA&#xff1a;Vector-based Random Matrix Adaptation》 论文地址&#xff1a;https://arxiv.org/pdf/2310.11454.pdf 相关博客 【自然语言处理】【大模型】VeRA&#xff1a;可调参数比LoRA小10倍的低秩微调方法 【自…

阿里微服务质量保障系列:性能监控

什么是性能监控&#xff0c;以及性能监控的对象有哪些。 伴随着突发流量、系统变更或代码腐化等因素&#xff0c;性能退化随时会发生。如在周年庆大促期间由于访问量暴涨导致请求超时无法下单&#xff1b;应用发布变更后&#xff0c;页面频繁卡顿导致客诉上升&#xff1b;线上…
最新文章