传统时间格式化的线程安全问题
测试线程安全问题
新建测试类
package com.dance.java8.day01.date;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.*;public class TestSimpleDateFormat {public static void main(String[] args) throws ExecutionException, InterruptedException {SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyyMMdd\");ExecutorService executorService = Executors.newFixedThreadPool(10);Callable<Date> callable = () -> simpleDateFormat.parse(\"20161218\");List<Future<Date>> list = new ArrayList<>();for (int i = 0; i < 10; i++) {list.add(executorService.submit(callable));}for (Future<Date> dateFuture : list) {System.out.println(dateFuture.get());}}}
测试结果
Exception in thread \"main\" java.util.concurrent.ExecutionException: java.lang.NumberFormatException: multiple pointsat java.util.concurrent.FutureTask.report(FutureTask.java:122)at java.util.concurrent.FutureTask.get(FutureTask.java:192)at com.dance.java8.day01.date.TestSimpleDateFormat.main(TestSimpleDateFormat.java:26)Caused by: java.lang.NumberFormatException: multiple pointsat sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)at java.lang.Double.parseDouble(Double.java:538)at java.text.DigitList.getDouble(DigitList.java:169)at java.text.DecimalFormat.parse(DecimalFormat.java:2056)at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1867)at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)at java.text.DateFormat.parse(DateFormat.java:364)at com.dance.java8.day01.date.TestSimpleDateFormat.lambda$main$0(TestSimpleDateFormat.java:17)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
使用ThreadLocal解决线程安全问题
新建ThreadLocal类
package com.dance.java8.day01.date;import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class DateFormatThreadLocal {private static final ThreadLocal<DateFormat> dateformat = new ThreadLocal<DateFormat>(){@Overrideprotected DateFormat initialValue() {return new SimpleDateFormat(\"yyyyMMdd\");}};public static Date convert(String source) throws ParseException {return dateformat.get().parse(source);}}
修改测试类
package com.dance.java8.day01.date;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.*;public class TestSimpleDateFormat {public static void main(String[] args) throws ExecutionException, InterruptedException {// SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyyMMdd\");ExecutorService executorService = Executors.newFixedThreadPool(10);Callable<Date> callable = () -> DateFormatThreadLocal.convert(\"20161218\");List<Future<Date>> list = new ArrayList<>();for (int i = 0; i < 10; i++) {list.add(executorService.submit(callable));}for (Future<Date> dateFuture : list) {System.out.println(dateFuture.get());}}}
测试结果
Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016Sun Dec 18 00:00:00 CST 2016
使用新的日期API解决线程安全问题
新建测试类
package com.dance.java8.day01.date;import java.time.LocalDate;import java.time.format.DateTimeFormatter;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.*;public class TestSimpleDateFormatNewApi {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(10);// 格式化类DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(\"yyyyMMdd\");// localDateCallable<LocalDate> callable = () -> LocalDate.parse(\"20161218\",dateTimeFormatter);List<Future<LocalDate>> list = new ArrayList<>();for (int i = 0; i < 10; i++) {list.add(executorService.submit(callable));}for (Future<LocalDate> dateFuture : list) {System.out.println(dateFuture.get());}executorService.shutdown();}}
测试结果
2016-12-182016-12-182016-12-182016-12-182016-12-182016-12-182016-12-182016-12-182016-12-182016-12-18
新的日期API
使用LocalDate,LocalTime,LocalDateTime
- LocalDate,LocalTime,LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期,时间,日期和时间,他们提供了简单的日期或时间,并不包含当前的额时间信息.也不包含与时区相关的信息
- 注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法
LocalDateTime
@Testpublic void test1(){// 获取当前时间LocalDateTime localDateTime = LocalDateTime.now();// 打印System.out.println(\"当前时间为:\"+localDateTime);// 指定日期LocalDateTime of = LocalDateTime.of(2021, 12, 4, 17, 49, 12);System.out.println(\"指定日期和时间:\"+of);// 日期时间计算// + 1 daySystem.out.println(\"添加一天:\" + localDateTime.plusDays(1));// -1 daySystem.out.println(\"减去一天:\" + localDateTime.plusDays(-1));// -3 yearSystem.out.println(\"减去三年:\" + localDateTime.minusYears(3));// 获取System.out.println(localDateTime.getYear());System.out.println(localDateTime.getMonthValue());System.out.println(localDateTime.getDayOfMonth());System.out.println(localDateTime.getHour());System.out.println(localDateTime.getMinute());System.out.println(localDateTime.getSecond());}
执行结果
当前时间为:2021-12-04T17:56:57.172指定日期和时间:2021-12-04T17:49:12添加一天:2021-12-05T17:56:57.172减去一天:2021-12-03T17:56:57.172减去三年:2018-12-04T17:56:57.1722021124175657
LocalDate和LocalTime
参考LocalDateTime
使用Instant
Instant
Instant : 时间戳(以Unix 元年: 1970年1月1日 00:00:00 到某个时间之间的毫秒值)
@Testpublic void test2(){Instant now = Instant.now();System.out.println(\"时间为:\"+now); // 默认获取UTC 时区 格林尼治时间// 小时偏移量计算OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));System.out.println(\"偏移后的时间:\"+offsetDateTime);// 转换为毫秒System.out.println(\"毫秒:\"+now.toEpochMilli());System.out.println(\"系统:\"+System.currentTimeMillis());// 偏移开始时间Instant instant = Instant.ofEpochSecond(60);System.out.println(\"元年偏移时间:\"+instant);}
执行结果
时间为:2021-12-04T10:10:50.324Z偏移后的时间:2021-12-04T18:10:50.324+08:00毫秒:1638612650324系统:1638612650428元年偏移时间:1970-01-01T00:01:00Z
使用Duration
Duration
@Testpublic void test3() throws InterruptedException {// 时间间隔Instant start = Instant.now();Thread.sleep(1000);Instant end = Instant.now();Duration between = Duration.between(start, end);System.out.println(\"时间间隔为:\"+between.getSeconds());LocalTime startTime = LocalTime.now();Thread.sleep(1000);LocalTime endTime = LocalTime.now();long seconds = Duration.between(startTime, endTime).getSeconds();System.out.println(\"时间间隔为:\" + seconds);}
执行结果
时间间隔为:1时间间隔为:1
使用Period
Period
@Testpublic void test4(){LocalDate now = LocalDate.now();LocalDate localDate = LocalDate.of(2022,3,4);Period between = Period.between(now, localDate);System.out.println(\"日期间隔:\"+between);}
执行结果
日期间隔:P3M
日期的操纵
- TemporalAdjuster:时间矫正器,有时我们可能需要获取列如:将日期调整到\”下个周期\”等操作
- TemporalAdjusters:该类通过静态方法提供了大量的常用TemporalAdjuster的实现
时间矫正器(TemporalAdjuster)
@Testpublic void test5(){LocalDateTime now = LocalDateTime.now();System.out.println(\"当前时间为:\"+now);// 指定日期为几号LocalDateTime localDateTime = now.withDayOfMonth(10);System.out.println(\"with date after:\"+localDateTime);// 时间矫正器// 调整到下周日LocalDateTime with = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));System.out.println(\"下周日为:\"+with);// 自定义下一个工作日LocalDateTime workDay = now.with(l -> {LocalDateTime work = (LocalDateTime) l;DayOfWeek dayOfWeek = work.getDayOfWeek();switch (dayOfWeek) {case FRIDAY:return work.plusDays(3);case SATURDAY:return work.plusDays(2);default:return work.plusDays(1);}});System.out.println(\"下一个工作日:\"+workDay);}
执行结果
当前时间为:2021-12-04T21:45:33.042with date after:2021-12-10T21:45:33.042下周日为:2021-12-05T21:45:33.042下一个工作日:2021-12-06T21:45:33.042
使用DateTimeFormatter
DateTimeFormatter
@Testpublic void test6(){// 使用提供的格式化类DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE;LocalDateTime now = LocalDateTime.now();String format = now.format(isoDate);System.out.println(format);// 自定义格式化DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");String format1 = now.format(dateTimeFormatter);System.out.println(format1);}
执行结果
2021-12-042021-12-04 22:19:10
时区的处理
- Java8中假如了对时区的支持,带时区的时间分别为:
- ZonedDate,ZonedTime,ZonedDateTime
- 其中每个时区都对应着ID,地区ID都为 \”{区域}/{城市}\”的格式
- 例如:Asia/Shanghai等
- ZondId:该类中包含了所有的时区信息
- getAvailableZoneIds():可以获取所有时区的时区信息
- of(id):用指定的时区信息获取ZoneId对象
ZonedDateTime
@Testpublic void test7(){// 打印所有时区// ZoneId.getAvailableZoneIds().forEach(System.out::println);// 指定时区获取时间LocalDateTime now = LocalDateTime.now(ZoneId.of(\"Asia/Shanghai\"));System.out.println(now);// 获取携带时区ZonedDateTime zonedDateTime = now.atZone(ZoneId.of(\"Asia/Shanghai\"));System.out.println(zonedDateTime);}
执行结果
2021-12-04T22:39:25.8812021-12-04T22:39:25.881+08:00[Asia/Shanghai]
若有收获,就点个赞吧
作者:彼岸舞
时间:2021\\12\\13
内容关于:Java
本文属于作者原创,未经允许,禁止转发