版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rubulai/article/details/89099572
问题
老的时间日期API都存在线程安全问题,因为它们的实例的值都是可变的,多个线程操作同一个实例的时候就会产生线程安全问题。新的时间日期API解决了这个问题,每次改变值都会新创建一个时间日期等实例对象,这样就不存在多个线程操作同一个对象的问题,也就避免了线程安全问题。新的时间日期API都在java.time包下,该包下的实例都是不可变的,也就是说只要变化就会产生新的实例,类似于String,避免了线程安全问题。
示例
1、多线程日期格式化:多个线程会同时操作同一个DateFormat实例,可能出现线程安全问题
public static void main(String args[]) throws InterruptedException, ExecutionException {
//多个线程会同时操作该DateFormat实例,就可能出现线程安全问题
DateFormat df = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return df.parse("20190408");
}
};
//创建线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
//线程池中的线程执行任务,将结果放在Future中
results.add(pool.submit(task));
}
for (Future<Date> future : results) {
System.out.println(future.get());
}
pool.shutdown();
}
某一次的运行结果:
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Mon Apr 08 00:00:00 CST 2019
Tue Jun 08 00:00:00 CST 2376
Tue Jun 08 00:00:00 CST 1
2、使用ThreadLocal解决线程安全问题
①使用ThreadLocal编写工具类:ThreadLocal为变量在每个线程中都创建一个副本,每个线程只可以访问自己内部的副本变量,避免线程安全问题
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date format(String source) throws ParseException {
return df.get().parse(source);
}
}
ThreadLocal的知识参考:深入剖析ThreadLocal
②使用本地线程变量中的DateFormat实例:避免线程安全问题
public static void main(String args[]) throws InterruptedException, ExecutionException {
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
//使用本地线程变量中的DateFormat实例
return DateFormatThreadLocal.format("20190408");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(pool.submit(task));
}
for (Future<Date> future : results) {
System.out.println(future.get());
}
pool.shutdown();
}
3、使用Java8的LocalDate,不需要使用ThreadLocal
public static void main(String args[]) throws InterruptedException, ExecutionException {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20190408", dtf);
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<LocalDate>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(pool.submit(task));
}
for (Future<LocalDate> future : results) {
System.out.println(future.get());
}
pool.shutdown();
}