前言

本次参加了2月份的征文活动,说是对时间的处理问题,我这有2个点需要分享一下,一个是上大学的时候碰到的,还有就是在工作中遇到的由于【SimpleDateFormat线程不安全】在多线程时间初始化的时候遇到的异常问题以及解决方案。希望能为大家创造一些价值。

目录

前言

1、丢失的8小时去哪里了

Java计算时间戳转换当前时分秒

转换成秒计算小时

2、SimpleDateFormat线程不安全,多线程初始化异常解决方案

异常复现

异常示例代码:

异常输出效果

异常源码分析

具体解决方案示例(100%解决,自己项目就这么用的)

无异常效果

总结


1、丢失的8小时去哪里了

在当年大二选修课的时候就遇到了这个问题,是时间戳转换成时间的时候,如果是自己来计算则会少了8个小时,用给定的函数就直接出来了,当时又不会配置查看源码,很苦恼,如果当时知道CSDN就好了,直接就能收到,所以当时是一直不知道为啥,后来问老师才知道的,我们今天就再来算一算,在这个分析过程中来看看具体是因为什么。

Java计算时间戳转换当前时分秒

Date date = new Date();
// 获取当前的时间戳·单位毫秒·21时15分32秒
long nowTime = date.getTime();

输出时间戳:这个时间戳的单位是毫秒。

在这里我们是根本看不出来是为啥的。接下来我们来一个一个的计算。

转换成秒计算小时

毫秒换算成秒

long second = nowTime / 1000;

换算成当前秒

long seconds = second % 60;

换算成当前分钟

long minutes = second / 60 % 60;

换算成小时

long hours = minutes / 60 % 24;

我们可以获取到:

很明显,我们计算的小时是有问题的,这个时间戳的时间是:【21时15分32秒】。可是时间换算完毕是13时,很明显21-13=8,相差8个小时,这个时候我们就很懵逼,咋回事呢?

我记得很早以前,我还只会VB语言的时候就遇到过这个问题。后来老师说,咱们是东八区我一下就明白了。

原来我们在东八区,所以我们的地区时应该在这个时间戳的基础上加上8个小时就对了。故而有以下代码:

package com.item.action;import java.util.Date;public class Main {public static void main(String[] args) {// TODO Auto-generated method stub
//      Date date = new Date();
//      // 获取当前的时间戳·单位毫秒
//      long nowTime = date.getTime();
//      System.out.println(nowTime);long nowTime = 1676985332143l;// 获取秒long second = nowTime / 1000;System.out.println(second + "s");// 获取分钟long seconds = second % 60;System.out.println(seconds + "s");long minutes = second / 60;System.out.println(minutes % 60 + "min");// 获取小时long hours = minutes / 60 % 24 + 8;System.out.println(hours + "h");System.out.println(hours+"时"+(minutes % 60)+"分"+seconds+"秒");}}

输出效果:

补上8个小时就是正确的时间了,这个类型题在蓝桥杯上也是出现过的,大家可以搜一搜,前三题,那个题目我倒是忘记了。

最后对于这个问题我们来看看百度上怎么说的:

东八区(UTC/GMT+08:00)是比世界协调时间(UTC)/格林尼治时间(GMT)快8小时的时区。

你看看,有了这句话就一下豁然开朗,我们计算的事件就是少了8个小时,所以加上就行了。

这里我找到了地区时的列表,可供大家查阅:

UTC-12: 国际日期变更线以西12小时
UTC-11: 标准时间时减去11小时
UTC-10: 标准时间时减去10小时
UTC-9: 标准时间时减去9小时
UTC-8: 标准时间时减去8小时
UTC-7: 标准时间时减去7小时
UTC-6: 标准时间时减去6小时
UTC-5: 标准时间时减去5小时
UTC-4: 标准时间时减去4小时
UTC-3: 标准时间时减去3小时
UTC-2: 标准时间时减去2小时
UTC-1: 标准时间时减去1小时
UTC: 标准时间·也就是全世界约定好的时间点
UTC+1: 标准时间时加上1小时
UTC+2: 标准时间时加上2小时
UTC+3: 标准时间时加上3小时
UTC+4: 标准时间时加上4小时
UTC+5: 标准时间时加上5小时
UTC+6: 协标准时间加上6小时
UTC+7: 标准时间时加上7小时
UTC+8: 标准时间时加上8小时
UTC+9: 标准时间时加上9小时
UTC+10: 标准时间时加上10小时
UTC+11: 标准时间时加上11小时
UTC+12: 标准时间时加上12小时

根据自己国家的地区时来进行加减就能得到自己本国的具体时间了。

2、SimpleDateFormat线程不安全,多线程初始化异常解决方案

这个问题挺坑的,只要多线程获取的时候就会格式化失败,复现代码不复杂,我就直接写了一个,并且没有进行大规模测试。

异常复现

这里直接new一个SimpleDateFormat就行,但是一定要给个static,这样就防止了各种new出现对内存的消耗

异常示例代码:

可以直接复制用来自己的测试,我没有写包名,方便大家。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class Demo {/*** 项目中·为了防止无限new就设置的静态变量*/static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static Date parseToDate(String timeStr) throws ParseException {return format.parse(timeStr);}public static void main(String[] args) {// TODO Auto-generated method stub/*** 我们不多测试,仅仅小小的多线程处理,就3个。*/for (int i = 0; i < 3; i++) {new Thread() {@Overridepublic void run() {try {System.out.println(parseToDate("2023-02-23 08:25:38"));} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}.start();}}
}

异常输出效果

很直接的看到,第一个肯定是输出成功了的,但是后面获取的时候就出现了异常,但是它直说FOR input string输入字符串,但是我们不知道底层是啥的话很难分析为啥,所以我们得对源码进行分析一下。

异常源码分析

首先我们来看SimpDateFormat的类,能看到是直接继承了DateFormat,我们要分析的就是它们两个。

我们看看SimpDateFormat类里面重写了DateFormat中的parse函数。

代码中我们能看到【CalendarBuilder】这个对象,在1532行能看到是通过【establish】将【calendar】设置到属性中,在1537行能看到具体的操作。

calendar是父类DateFormat类的共享变量,可以被多个线程访问到

所以,当SimpleDateFormat被声明为static的时候时就是线程不安全的,多个线程同时操作,肯定会显现访问异常。

通过查看format()发现有一行calendar.setTime(date);操作的是共享变量calendar,那这么一看就很明显了——线程不安全。

具体解决方案示例(100%解决,自己项目就这么用的)

这里在解决的时候我们使用【DateTimeFormatter】来解决,但是这个类在JDK1.8之后才会有,这里声明一下,是【JAVA_JDK1.8】,【LocalDateTime】本身绝对是线程安全的,那么我们就可以直接使用它来替换,看下面的代码就能看到,但是时间的类型这里需要使用【LocalDateTime】来处理。

package test;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;public class Demo1 {static final DateTimeFormatter dtformat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");public static LocalDateTime parseToDate(String timeStr) {return LocalDateTime.parse(timeStr,dtformat);}public static void main(String[] args) {// TODO Auto-generated method stub/*** 既然我们做了处理,那么我们就来300个线程试一试<br/>* 开两个循环一个循环150次。*/for (int i = 0; i < 150; i++) {new Thread() {@Overridepublic void run() {System.out.println(parseToDate("2023-02-23 08:25:38"));}}.start();}for (int i = 0; i < 150; i++) {new Thread() {@Overridepublic void run() {System.out.println(parseToDate("2023-02-23 08:25:38"));}}.start();}}}

无异常效果

到这里,我们就彻底解决了这个项目部署的时候遇到时间初始化的问题。

希望能对初学者有一定的帮助,很多项目在初始化的时候都是要使用到时间,那么当出现问题的时候大概都是这个问题,使用我的方法就能迎刃而解了。

总结

我们初学的孩子们肯定都是在使用SimpleDateFormat来格式化时间,很少会遇到多线程的时候,所以是根本没有感觉的,但是这个bug是客观存在的,在class中我们甚至看到了开发者留的注释信息,虽然是对源码进行分析找到了原因,但是想彻底的更换固有思维逻辑还是需要一定的时间的,包括我在内,最开始在企业搞开发的时候还好,遇到大型初始化的不多,但是后来自己开始掌控项目后发现,真的有很多你开发的时候不会注意到是事情就都出现了,毕竟你已经开始统筹全局。以后遇到时间格式化的时候使用【DateTimeFormatter】来格式化,线程安全,保证不会出现这类异常了。

丢失的8小时去哪里了?SimpleDateFormat线程不安全,多线程初始化异常解决方案相关推荐

  1. springboot 多了8小时_日本人不明白:中国的奶茶有多好喝,值得排队8小时去买?...

    日本人不明白:中国的奶茶有多好喝,值得排队8小时去买? 最近有许多的网红奶茶店兴起,尤其是在冬季,加料十足的热奶茶就成为了年轻人的心头之好,就拿最近在武汉新开的首家茶颜悦色来说,每天的队伍都能排老长老 ...

  2. hashmap是线程安全的吗?怎么解决?_解决SimpleDateFormat线程安全问题

    SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须通过加锁等方式保证线程安全. 例如下面一段代码,启动10个线程,同时使用一个`Simple ...

  3. 为什么SimpleDateFormat线程不安全? 侵立删

    转自:https://mp.weixin.qq.com/s/2uzr800WYtu4R0hycfGruA 在日常开发中,我们经常会用到时间相关类,我们有很多办法在Java代码中获取时间.但是不同的方法 ...

  4. SimpleDateFormat线程不安全

    SimpleDateFormat线程不安全 http://www.cnblogs.com/peida/archive/2013/05/31/3070790.html dateUtil替换 posted ...

  5. SimpleDateFormat线程不安全了?这里有5种解决方案

    摘要:我们知道SimpleDateFormat是线程不安全,本文会介绍多种解决方案来保证线程安全. 本文分享自华为云社区<java的SimpleDateFormat线程不安全出问题了,虚竹教你多 ...

  6. SimpleDateFormat 线程不安全及解决方案

    SimpleDateFormat 线程不安全及解决方案 参考文章: (1)SimpleDateFormat 线程不安全及解决方案 (2)https://www.cnblogs.com/yangzhen ...

  7. android calendar 24小时制,Android 使用SimpleDateFormat以及Calendar转换时间为12小时制和24小时制时间格式...

    由于项目需要,有些地方要使用12小时制时间格式,而有些地方使用的24小时制时间格式 通过研究代码,原来...So easy,现将实现的方法写下来和大家分享 使用SimpleDateFormat时格式化 ...

  8. acadres.dll文件丢失怎么办?怎么去修复?

    大家在玩游戏的时候,有没有发现有时候会跳出来一个acadres.dll丢失的框框,然后游戏无法打开运行,其实遇到这种情况还是很好解决的,主要是由于dll文件缺失引起的,下面我们一起来了解一下acadr ...

  9. 为什么手机版scp进不去_SCP1471,只属于你一人你的异常狗子,scp基金会系列

    以下为视频文字稿,想看视频的可以在B站/爱奇艺等平台,搜索「ONE好奇」 本公众号源于爱好 未经过具体推广 个人时间也实在有限 我希望能有更多的爱好者加入进来一起讨论SCP问题 有什么想法的可以留言 ...

最新文章

  1. 计算机基础1模拟题,计算机基础模拟题1(有答案).doc
  2. ubuntu指令模式修改IP等信息
  3. Openssl-MD5
  4. docker 运行windows程序_如何从Windows上运行任何Linux图形GUI程序?
  5. 全球Top10最佳移动统计分析sdk
  6. linux 生成rsa密钥,linux下生成rsa密钥的方法
  7. 网易云音乐ncm格式和QQ音乐qcm格式的学习记录
  8. 《思维训练500题》
  9. 用计算机画画内容,【经验】怎么用电脑绘画?
  10. 将R Markdown文档变成互动体验
  11. 3ds Max2021软件安装包+安装教程
  12. bat编程和vbs编程入门
  13. 面试之springboot是什么?
  14. AlertManager实现webhook告警(使用Postman测试)
  15. iPhone 计算机 桌面,变身iOS?让Windows 10的桌面和苹果一样美
  16. SumaTraPDF
  17. vue element ui合并表格(合并某列的行数据)
  18. php文字转语音amr,如何将文字转成语音?这几个方法一分钟搞定!
  19. Codeforces Round #672 (Div. 2) Pokémon Army
  20. SharpDevelop插件开发手册

热门文章

  1. 【Flask学习】2.2模板之设计
  2. 如何在线将PDF转成Excel
  3. ROS教程四——编写Publisher和Subscriber节点(Python篇)
  4. 如何用css实现百叶窗效果
  5. BurpSuite安装(附安装包)
  6. golang之go mod自动下载私有仓库gitlab中的包
  7. Java Web下载Excel模板
  8. LightOJ - 1176-Getting a T-shirt (最大流)
  9. SparkStreaming与Hudi整合报错
  10. 6大差异盘点:公募基金券商交易模式和直接进场交易模式