点击蓝色“ 程序猿DD ”关注我
回复“ 资源 ”获取独家整理的学习资料!
格式化和解析日期是个(痛苦的)日常任务。每天,它都让我们很头疼。
在 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:当我们使用实例变量时,应始终检查其是否是一个线程安全类。
正如文档所述,我们为每个线程持有一个独立的变量来解决该问题。如果我们想共享对象?有什么解决方案?
这个问题可以通过使用 ThreadLocal
变量来解决。 ThreadLocal
的 get()
方法将为我们提供当前线程的正确值。
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);
}
}
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);
}
}
Java 8 的解决方案使用不可变类,这是解决多线程问题的好方法。不可变类本质上是线程安全的,所以请尽可能地使用它们。
Happy coding!
留言交流不过瘾? 添加微信: zyc_enjoy
根据指引加入各种主题讨论群
推荐阅读
这几款好用超赞的 Google Chrome插件送给你!
IntelliJ IDEA 2019.2最新解读
Spring Cloud与Dubbo的完美融合之手
狡猾的 AI 工程师,编个故事骗走 2 亿人民币...
日均7亿交易量,如何设计高可用的MySQL架构?
签到计划
活动介绍 : 自律到极致-人生才精致:第13期
活动奖励: 《Spring Cloud微服务: 入门、实战与进阶》 x 10
扫描下方二维码, 签到参与
推荐关注:锅外的大佬