LocalDateTime 和 Date 的比较和区别
LocalDate、LocalTime、LocalDateTime 都是 JDK1.8 新增的,为什么有了 Date 还要这几个呢?
在代码中我们直接使用 new Date() 直接输出,如果不格式化,结果如下
Tue Nov 03 11:01:22 CST 2020
可读性不行,如果要格式化就必须使用 SimpleDateFormat ,但是 SimpleDateFormat 时线程不安全的。
直接看看源码吧,calendar 是共享变量,并且没有对它做线程安全控制。
当多个线程同时使用相同的 SimpleDateFormat 对象(静态对象)调用 format 方法时,多个线程会同时调用 calendar.setTime(),可能一个线程刚设置好 time 值,另一个线程马上就把设置的 time 给修改了,导致得不到预期的结果。
// Called from Format after creating a FieldDelegate
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;
}
SimpleDateFormat 除了 format 是线程不安全以外,parse 方法也是线程不安全的。
parse 方法实际取用 calb.establish(calendar).getTime() 的时间来解析。
calb.establish(calendar) 里主要完成了:
- 重置日期对象 cal 的属性值;
- 使用 calb 中的属性设置 cal;
- 返回设置好的 cal 对象;
但这三步操作并不是原子操作,所以也是线程不安全的。
多线程并发如何保证线程安全?
- 避免线程之间共享一个 SimpleDateFormat 对象,每个线程使用时都创建一个 SimpleDateFormat 对象(创建和销毁对象的开销大)
- 对使用 format 和 parse 方法的地方进行加锁(线程阻塞性能差)
- 使用 ThreadLocal 保证每个线程最多只创建一次 SimpleDateFormat (较好的方法)
Date 对时间处理比较麻烦
想获取某年、某月、某星期,还有时间偏移等,处理起来太麻烦。
并且 getYear()、getMonth() 等方法都被弃用了。
使用 JDK1.8 全新的日期和时间 API
LocalDate,日期,构造指定的年月日
System.out.println(LocalDate.now());
// 结果:2020-11-03
System.out.println(LocalDate.of(2019, 11, 11));
// 结果:2019-11-11
获取年、月、日、星期几
LocalDate localDate = LocalDate.now();
// 2020
System.out.println(localDate.getYear());
// 2020
System.out.println(localDate.get(ChronoField.YEAR));
// NOVEMBER
System.out.println(localDate.getMonth());
// 11
System.out.println(localDate.get(ChronoField.MONTH_OF_YEAR));
// 3
System.out.println(localDate.getDayOfMonth());
// 3
System.out.println(localDate.get(ChronoField.DAY_OF_MONTH));
// TUESDAY
System.out.println(localDate.getDayOfWeek());
// 2
System.out.println(localDate.get(ChronoField.DAY_OF_WEEK));
获取时分秒
LocalTime localTime = LocalTime.now();
// 11:53:50.510
System.out.println(localTime);
System.out.println(localTime.getHour());
System.out.println(localTime.get(ChronoField.HOUR_OF_DAY));
System.out.println(localTime.getMinute());
System.out.println(localTime.get(ChronoField.MINUTE_OF_HOUR));
System.out.println(localTime.getSecond());
System.out.println(localTime.get(ChronoField.MICRO_OF_SECOND));
LocalDateTime 获取年月时分秒,相当于 LocalDate + LocalTime
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);
LocalDateTime localDateTime3 = localDate.atTime(localTime);
LocalDateTime localDateTime4 = localTime.atDate(localDate);
和 SimpleDateFormat 相比,DateTimeFormatter 是线程安全的。
封面图,拍摄于 2019/04/09 深圳市东西涌
有机会多去海边看看风景!
写在最后
如果觉得我的文章对你有帮助,可以关注一下我的微信公众号支持一下,万分感谢!
- 本文链接: https://www.lvhaosir.cn/archives/java8-localdatetime
- 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!