不简单的 Java SimpleDateFormat

点击左上角蓝字,关注“锅外的大佬”640?wx_fmt=gif

专注分享国外最新技术内容

事实证明,Java 的 SimpleDateFormat 并没有那么简单。

格式化和解析日期是个(痛苦的)日常任务。每天,它都让我们很头疼。

在 Java 中格式化和解析日期的一种常见方法是使用 SimpleDateFormat。下面是我们用到的一个公共类。

import java.text.ParseException;	
import java.text.SimpleDateFormat;	
import java.util.Date;	

	
public final class DateUtils {	

	
    public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");	

	
    private DateUtils() {}	

	
    public static Date parse(String target) {	
        try {	
            return SIMPLE_DATE_FORMAT.parse(target);	
        } catch (ParseException e) {	
            e.printStackTrace();	
        }	
        return null;	
    }	

	
    public static String format(Date target) {	
        return SIMPLE_DATE_FORMAT.format(target);	
    }	

	
}

你觉得它会像我们预期的那样进行工作么?让我们试一试。

private static void testSimpleDateFormatInSingleThread() {	
    final String source = "2019-01-11";	
    System.out.println(DateUtils.parse(source));	
}	

	
// Fri Jan 11 00:00:00 IST 2019

是的,它奏效了。接下来再用多线程再试一试。

private static void testSimpleDateFormatWithThreads() {	
    ExecutorService executorService = Executors.newFixedThreadPool(10);	

	
    final String source = "2019-01-11";	

	
    System.out.println(":: parsing date string ::");	
    IntStream.rangeClosed(0, 20)	
            .forEach((i) -> executorService.submit(() -> System.out.println(DateUtils.parse(source))));	

	
    executorService.shutdown();	
}

这是我得到的结果:

:: parsing date string ::	
... omitted	
Fri Jan 11 00:00:00 IST 2019Sat Jul 11 00:00:00 IST 2111Fri Jan 11 00:00:00 IST 2019	
... omitted

结果很有意思,不是么?这是我们大多数人在 Java 中格式化日期时常犯的错误。为什么?因为我们不了解线程安全。以下是 Java doc 中关于 SimpleDateFormat 的内容:

日期格式是不同步的。

建议为每个线程创建独立的格式实例。

如果多个线程同时访问一个格式,则它必须是外部同步的。

Tip:当我们使用实例变量时,应始终检查其是否是一个线程安全类。

正如文档所述,我们为每个线程持有一个独立的变量来解决该问题。如果我们想共享对象?有什么解决方案?

1. 方案一:ThreadLocal

这个问题可以通过使用 ThreadLocal 变量来解决。ThreadLocalget() 方法将为我们提供当前线程的正确值。

import java.text.ParseException;	
import java.text.SimpleDateFormat;	
import java.util.Date;	

	
public final class DateUtilsThreadLocal {	

	
    public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));	

	
    private DateUtilsThreadLocal() {}	

	
    public static Date parse(String target) {	
        try {	
            return SIMPLE_DATE_FORMAT.get().parse(target);	
        } catch (ParseException e) {	
            e.printStackTrace();	
        }	
        return null;	
    }	

	
    public static String format(Date target) {	
        return SIMPLE_DATE_FORMAT.get().format(target);	
    }	

	
}

2. 方案二:Java 8 中线程安全的日期时间 API

Java 8 引入了一套新的日期时间 API。我们有一个更好的、麻烦更少的 SimpleDateFormat 替代品。如果我们真的需要坚持使用 SimpleDateFormat,可以继续使用 ThreadLocal。但是当有更好的选择时,我们应考虑使用它。

Java 8 引入了几个线程安全的日期类。

以下是 Java doc 的描述:

本类是不可变的,且线程安全的。

这些类是更加值得研究的,包括 DateTimeFormatter,[OffsetDateTime], ZonedDateTime,LocalDateTime ,LocalDate 和 LocalTime。

我们的解决方案:

import java.time.LocalDate;	
import java.time.format.DateTimeFormatter;	

	
public class DateUtilsJava8 {	

	
    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");	

	
    private DateUtilsJava8() {}	

	
    public static LocalDate parse(String target) {	
        return LocalDate.parse(target, DATE_TIME_FORMATTER);	
    }	

	
    public static String format(LocalDate target) {	
        return target.format(DATE_TIME_FORMATTER);	
    }	

	
}

3. 结论

Java 8 的解决方案使用不可变类,这是解决多线程问题的好方法。不可变类本质上是线程安全的,所以请尽可能地使用它们。

Happy coding!

spring for all翻译组


8月福利来袭!关注公众号

后台回复003 ,领取7月翻译集锦~ 

往期福利回复001, 002即可领取  

640?wx_fmt=gif

Top11 构建和测试API的工具

Spring Boot 面试的十个问题

开车!Spring Batch 入门级示例教程!

右上角按钮分享给更多人哦~smiley_63.pngsmiley_63.png

640?wx_fmt=png

来都来了,点个在看再走吧~~~

640?wx_fmt=gif

CCF大数据与计算智能大赛-面向电信行业存量用户的智能套餐个性化匹配模型联通赛-复赛第二名-【多分类,embedding】.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值