问题背景
在公司开发统计数据类项目的时候,遇到一个统计接口需要请求3万次数据库,单线程执行实在是太慢,每次都需要好几分钟的时间,所以便想着使用多线程来提高一下执行速度。
这个项目是一个电力统计系统,发电厂分为火力发电厂,水力发电厂和新能源发电厂,该接口需要汇总的是:每个月—每种类型的发电厂所发电量。
例如:一月份:火力发电厂发了20万千瓦时,水力发电厂发了10万千瓦时,新能源发电厂发了5万千瓦时。
问题重现
同一个SimpleDateFormat实例使用在多线程中出现的问题(本例子是打印从当前时间开始以及往后的12个月份的年月信息)
public static Date addMonth(Date date,int num) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.MONTH,date.getMonth() + num);
return calendar.getTime();
}
@Test
public void test02() throws InterruptedException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
Date nowDate = new Date();
Calendar calendar = Calendar.getInstance();
//多线程
for (int i=0; i <=12; i++) {
final int j = i;
Date begDate = this.addMonth(nowDate,j);
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(dateFormat.format(begDate));
}
});
thread01.start();
}
//非多线程
/* for (int i=0; i <=12; i++) {
final int j = i;
Date begDate = TestThread.addMonth (nowDate,j);
System.out.println(dateFormat.format(begDate));
}*/
Thread.sleep(3000);
}
多线程输出的其中一种错误结果:
在上面的图片中,本应该输出2021-04到2022-04的,但是因为在线程中使用了同一个实例的SimpleDateFormat,使得2021-04变成了2021-06,导致错误的结果。
改进
方法一:多线程部分将format操作移出线程:
//多线程
for (int i=0; i <=12; i++) {
final int j = i;
Date begDate = this.addMonth(nowDate,j);
String formatDate = dateFormat.format(begDate);
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(formatDate);
}
});
thread01.start();
}
方法二:使用线程安全的DateTimeformatter类
@Test
public void test02() throws InterruptedException {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
LocalDate nowDate = LocalDate.now();
//线程安全多线程
for (int i=0; i <=12; i++) {
final int j = i;
LocalDate begDate = nowDate.plusMonths(j);
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(formatter.format(begDate));
}
});
thread01.start();
}
}