iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么在Java8中实现一个线程安全日期类
  • 569
分享到

怎么在Java8中实现一个线程安全日期类

2023-06-14 13:06:55 569人浏览 八月长安
摘要

这期内容当中小编将会给大家带来有关怎么在Java8中实现一个线程安全日期类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。LocalDateTimeJava8新特性之一,新增日期类。在项目开发过程中经常遇到

这期内容当中小编将会给大家带来有关怎么在Java8中实现一个线程安全日期类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

LocalDateTime

Java8新特性之一,新增日期类。

项目开发过程中经常遇到时间处理,但是你真的用对了吗,理解阿里巴巴开发手册中禁用static修饰SimpleDateFORMat吗

通过阅读本篇文章你将了解到:

  • 为什么需要LocalDate、LocalTime、LocalDateTime【java8新提供的类】

  • Java8新的时间api的使用方式,包括创建、格式化、解析、计算、修改

可以使用Instant代替 Date,LocalDateTime代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat。

SimpleDateFormat线程不安全

Date如果不格式化,打印出的日期可读性差

Tue Sep 10 09:34:04 CST 2019

使用SimpleDateFormat对时间进行格式化,但SimpleDateFormat是线程不安全的 SimpleDateFormat的format方法最终调用源码

private StringBuffer format(Date date, StringBuffer toAppendTo,                              FieldDelegate delegate) {        // Convert input date to time field list        calendar.setTime(date);         boolean useDateFormatSymbols = useDateFormatSymbols();         for (int i = 0; i < compiledPattern.length; ) {            int tag = compiledPattern[i] >>> 8;            int count = compiledPattern[i++] & 0xff;            if (count == 255) {                count = compiledPattern[i++] << 16;                count |= compiledPattern[i++];            }             switch (tag) {            case TAG_QUOTE_ASCII_CHAR:                toAppendTo.append((char)count);                break;             case TAG_QUOTE_CHARS:                toAppendTo.append(compiledPattern, i, count);                i += count;                break;             default:                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);                break;            }        }        return toAppendTo;    }

注意calendar.setTime(date);,Calendar类是里面基本都是final修饰的,calendar是共享变量,并且这个共享变量没有做线程安全控制。当多个线程同时使用相同的SimpleDateFormat对象【如用static修饰的SimpleDateFormat,一般会封装在工具类,复用】调用format方法时,多个线程会同时调用calendar.setTime方法,可能一个线程刚设置好time值另外的一个线程马上把设置的time值给修改了导致返回的格式化时间可能是错误的。

在多并发情况下使用SimpleDateFormat需格外注意:

SimpleDateFormat除了format方法是线程不安全以外,parse方法也是线程不安全的。parse方法实际调用alb.establish(calendar).getTime()方法来解析,alb.establish(calendar)方法里主要完成了

  • 重置日期对象cal的属性值

  • 使用calb(calBuilder)中属性设置cal

  • 返回设置好的cal对象

但是这三步不是原子操作

SimpleDateFormat如何保证线程安全

  • 避免线程之间共享一个SimpleDateFormat对象,每个线程使用时都创建一次SimpleDateFormat对象 => 创建和销毁对象的开销大

  • 对使用format和parse方法的地方进行加 => 线程阻塞性能差

  • 使用ThreadLocal保证每个线程最多只创建一次SimpleDateFormat对象 => 较好的方法

Date对时间处理比较麻烦,比如想获取某年、某月、某星期,以及n天以后的时间,如果用Date来处理的话真是太难了,你可能会说Date类不是有getYear、getMonth这些方法吗,获取年月日很Easy,但都被弃用了啊

Java8全新的日期和时间API

在使用Java程序操作数据库时,我们需要把数据库类型与Java类型映射起来。下表是数据库类型与Java新旧API的映射关系:

数据库对应Java类(旧)对应Java类(新)
DATETIMEjava.util.DateLocalDateTime
DATE  java.sql.DateLocalDate
TIME java.sql.Time LocalTime
TIMESTAMP java.sql.Timestamp LocalDateTime

 LocalDate

只会获取年月日

//获取当前年月日        LocalDate localDate = LocalDate.now();        //构造指定的年月日        LocalDate localDate1 = LocalDate.of(2019, 9, 10);        //获取年、月、日、星期几        int year = localDate.getYear();        int year1 = localDate.get(ChronoField.YEAR);        Month month = localDate.getMonth();        int month2 = localDate.get(ChronoField.MONTH_OF_YEAR);        int day = localDate.getDayOfMonth();        int day1 = localDate.get(ChronoField.DAY_OF_MONTH);        DayOfWeek dayOfWeek = localDate.getDayOfWeek();        int dayOfWeek1 = localDate.get(ChronoField.DAY_OF_WEEK);

LocalTime

只会获取几点几分几秒

//创建LocalTime        LocalTime localTime = LocalTime.of(13, 51, 10);        LocalTime localTime1 = LocalTime.now();        //获取小时        int hour = localTime.getHour();        int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);        //获取分        int minute = localTime.getMinute();        int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);        //获取秒        int second = localTime.getSecond();        int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);

LocalDateTime

获取年月日时分秒,等于LocalDate+LocalTime

//创建对象        LocalDateTime localDateTime = LocalDateTime.now();        LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);        //LocalDate+LocalTime-->LocalDateTime        LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);        LocalDateTime localDateTime3 = localDate.atTime(localTime);        LocalDateTime localDateTime4 = localTime.atDate(localDate);        //获取LocalDate        LocalDate localDate2 = localDateTime.toLocalDate();        //获取LocalTime        LocalTime localTime2 = localDateTime.toLocalTime();

ZonedDateTime

LocalDateTime总是表示本地日期和时间,要表示一个带时区的日期和时间,我们就需要ZonedDateTime

可以简单地把ZonedDateTime理解成LocalDateTimeZoneIdZoneIdjava.time引入的新的时区类,注意和旧的java.util.TimeZone区别。

创建一个ZonedDateTime对象

// 默认时区ZonedDateTime zbj = ZonedDateTime.now(); // 用指定时区获取当前时间ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York"));

结果:

2019-09-15T20:58:18.786182+08:00[Asia/Shanghai]
2019-09-15T08:58:18.788860-04:00[America/New_York]

另一种创建方式是通过给一个LocalDateTime附加一个ZoneId,就可以变成ZonedDateTime

LocalDateTime ldt = LocalDateTime.of(2019, 9, 15, 15, 16, 17);ZonedDateTime zbj = ldt.atZone(ZoneId.systemDefault());ZonedDateTime zny = ldt.atZone(ZoneId.of("America/New_York"));

时区转换

要转换时区,首先我们需要有一个ZonedDateTime对象,然后,通过withZoneSameInstant()将关联时区转换到另一个时区,转换后日期和时间都会相应调整。

ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));// 转换为纽约时间:ZonedDateTime zny = zbj.withZoneSameInstant(ZoneId.of("America/New_York"));

ZonedDateTime仍然提供了plusDays()等加减操作。

要特别注意,时区转换的时候,由于夏令时的存在,不同的日期转换的结果很可能是不同的。这是北京时间9月15日的转换结果:

2019-09-15T21:05:50.187697+08:00[Asia/Shanghai]
2019-09-15T09:05:50.187697-04:00[America/New_York]

这是北京时间11月15日的转换结果:

2019-11-15T21:05:50.187697+08:00[Asia/Shanghai]
2019-11-15T08:05:50.187697-05:00[America/New_York]

两次转换后的纽约时间有1小时的夏令时时差。涉及到时区时,千万不要自己计算时差,否则难以正确处理夏令时。有了ZonedDateTime,将其转换为本地时间就非常简单:

ZonedDateTime zdt = ...LocalDateTime ldt = zdt.toLocalDateTime();

转换为LocalDateTime时,直接丢弃了时区信息。

Instant

获取秒数或时间戳

//创建Instant对象        Instant instant = Instant.now();        //获取秒数        long currentSecond = instant.getEpochSecond();        //获取毫秒数        long currentMilli = instant.toEpochMilli();        long l = System.currentTimeMillis();

System.currentTimeMillis()也可以获取毫秒数。

日期计算

LocalDate、LocalTime、LocalDateTime、Instant为不可变对象,修改这些对象对象会返回一个副本

增加、减少年数、月数、天数等,以LocalDateTime为例

//修改LocalDate、LocalTime、LocalDateTime、Instant        LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10,                14, 46, 56);        //增加一年        localDateTime = localDateTime.plusYears(1);        localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);        //减少一个月        localDateTime = localDateTime.minusMonths(1);        localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);//通过with修改某些值        //修改年为2020        localDateTime = localDateTime.withYear(2020);        //修改为2022        localDateTime = localDateTime.with(ChronoField.YEAR, 2022);//还可以修改月、日

有些时候想知道这个月的最后一天是几号、下个周末是几号,通过提供的时间和日期API可以很快得到答案

LocalDate localDate = LocalDate.now();LocalDate localDate1 = localDate.with(TemporalAdjusters.firstDayOfYear());

比如通过firstDayOfYear()返回了当前年的第一天日期,还有很多方法这里不在举例说明

格式化时间

DateTimeFormatter默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过DateTimeFormatter的ofPattern方法创建自定义格式化方式

LocalDate localDate = LocalDate.of(2019, 9, 10);String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);//自定义格式化DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");String s3 = localDate.format(dateTimeFormatter);

解析时间

和SimpleDateFormat相比,DateTimeFormatter是线程安全的

LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);

DateTimeFormatter替代SimpleDateFormat

使用旧的Date对象时,我们用SimpleDateFormat进行格式化显示。使用新的LocalDateTimeZonedLocalDateTime时,我们要进行格式化显示,就要使用DateTimeFormatter

SimpleDateFormat不同的是,DateTimeFormatter不但是不变对象,它还是线程安全的。因为SimpleDateFormat不是线程安全的,使用的时候,只能在方法内部创建新的局部变量。而DateTimeFormatter可以只创建一个实例,到处引用。

//构造器1:传入格式字符串DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//构造器2:传入格式字符串和地区DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, yyyy-MMMM-dd HH:mm:ss", Locale.US);DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, yyyy-MMMM-dd HH:mm:ss", Locale.CHINA);

DateTimeFormatter底层原理

DateTimeFormatter线程安全的?为什么?

源码:

怎么在Java8中实现一个线程安全日期类

很明显,通过final修饰类,不可被继承,final修饰变量,做成了不可变类,类似String,不仅线程安全而且高效。全局可以只有一个对象,多个线程引用。

format和parse线程安全替代

使用LocalDateTime的format和parse方法,传入对应的DateTimeFormatter对象参数,实际也是调用DateTimeFormatter的format和parse方法,实现日期格式化和解析,是线程安全的。

DateTimeFormatter类解析LocalDateTime中的日期变量,转成StringBuilder返回。LocalDateTime等新出的日期类全是final修饰的类,不能被继承,且对应的日期变量都是final修饰的,也就是不可变类。赋值一次后就不可变,不存在多线程数据问题。

怎么在Java8中实现一个线程安全日期类

上述就是小编为大家分享的怎么在Java8中实现一个线程安全日期类了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网精选频道。

--结束END--

本文标题: 怎么在Java8中实现一个线程安全日期类

本文链接: https://www.lsjlt.com/news/271256.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么在Java8中实现一个线程安全日期类
    这期内容当中小编将会给大家带来有关怎么在Java8中实现一个线程安全日期类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。LocalDateTimeJava8新特性之一,新增日期类。在项目开发过程中经常遇到...
    99+
    2023-06-14
  • Java8新特性之线程安全日期类
    目录LocalDateTimeSimpleDateFormat线程不安全SimpleDateFormat如何保证线程安全Java8全新的日期和时间APILocalDateLocalT...
    99+
    2024-04-02
  • 怎么在Java8项目中实现一个函数式编程
    这期内容当中小编将会给大家带来有关怎么在Java8项目中实现一个函数式编程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。函数式的思考命令式编程一般我们实现一个系统有两种思考方式,一种专注于如何实现,比如下...
    99+
    2023-05-31
    java8 函数式编程 ava
  • 怎么在Python中利用tkinter实现一个日期选择器
    这篇文章主要介绍了怎么在Python中利用tkinter实现一个日期选择器,此处通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考价值,需要的朋友可以参考下:首先,定义一个类,叫Calendar# -*- ...
    99+
    2023-06-06
  • Java中怎么实现线程安全
    Java中怎么实现线程安全,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1、使用synchronized关键字synchronized关键字可以修饰方法和代码块,它的语义是...
    99+
    2023-06-16
  • 利用C++实现一个线程安全的map
    目录第一轮对话请求回复第二轮对话请求回复完整代码本文是使用ChatCPT生成的,最终的代码使用起来没问题。代码是通过两轮对话完善的,后面把对话合并后跑不出理想效果就没尝试了。 第一轮...
    99+
    2023-05-19
    C++实现线程安全的map C++线程安全的map C++ map
  • 怎么在java中利用Runnable实现一个线程
    怎么在java中利用Runnable实现一个线程?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用...
    99+
    2023-06-14
  • 怎么在java中实现一个多线程爬虫
    怎么在java中实现一个多线程爬虫?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android...
    99+
    2023-06-14
  • C#中怎么实现多线程安全
    C#中怎么实现多线程安全,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。C#多线程控制进度条之多线程安全的问题:我们知道 Windows 编程中有一个必须遵守的原则,那就是在一个...
    99+
    2023-06-17
  • java中怎么实现一个线程池
    本篇文章为大家展示了java中怎么实现一个线程池,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。有些人可能对线程池比较陌生,并且更不熟悉线程池的工作原理。所以他们在使用线程的时候,多数情况下都是new...
    99+
    2023-06-20
  • 怎么在Java8中使用Collectors实现一个求和功能
    怎么在Java8中使用Collectors实现一个求和功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。自定义工具类public class MyColle...
    99+
    2023-06-06
  • Python中如何实现一个线程安全的缓存对象
    Python中如何实现一个线程安全的缓存对象随着多线程编程在Python中的越来越被广泛应用,线程安全性变得愈发重要。在并发环境中,多个线程同时读写共享资源时,可能会导致数据不一致或者意外的结果。为了解决这个问题,我们可以使用线程安全的缓存...
    99+
    2023-10-22
    线程安全 缓存对象 Python 实现
  • Java中怎么安全组建一个系统线程组
    今天就跟大家聊聊有关Java中怎么安全组建一个系统线程组,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在 Java 中,除系统线程组外的每个线程组又隶属于另一个线程组,你可以在创建线...
    99+
    2023-06-17
  • android开发中怎么实现一个日期选择控件
    android开发中怎么实现一个日期选择控件?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。效果如下:具体实现方法为:先新建一个安卓项目DoubleDatePicker,在res...
    99+
    2023-05-31
    android roi
  • Java中怎么实现一个多线程程序
    Java中怎么实现一个多线程程序,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Java多线程程序设计详细解析一、理解Java多线程Java多线程是这样一种机制,它允许在程序中并...
    99+
    2023-06-17
  • Java8中怎么实现一个函数式接口
    这篇文章给大家介绍Java8中怎么实现一个函数式接口,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。以下我们继续深入Java8函数式编程模型public class Test1 { ...
    99+
    2023-05-30
    java8
  • C#中怎么定义一个线程类
    本篇文章为大家展示了C#中怎么定义一个线程类,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。C#线程类的定义实例://C#线程类的定义实例  using System;&...
    99+
    2023-06-17
  • 怎么在Android中实现一个多线程下载功能
    怎么在Android中实现一个多线程下载功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。布局      &nb...
    99+
    2023-05-30
    android 多线程
  • Java中ConcurrentHashMap是怎么实现线程安全的
    这篇文章主要介绍“Java中ConcurrentHashMap是怎么实现线程安全的”,在日常操作中,相信很多人在Java中ConcurrentHashMap是怎么实现线程安全的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希...
    99+
    2023-06-25
  • 怎么在Java中创建一个线程
    今天就跟大家聊聊有关怎么在Java中创建一个线程,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java中线程的创建有两种方式: 1.  通过继承Thread类,重...
    99+
    2023-05-31
    java 线程 ava
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作