先感谢微信一个老哥 薛华隆老哥的指导~~
多线程简述
我的理解就是解决一个请求在执行业务时能够并发执行,将本该一个人做的事情分别交给几个人做,具体详解请自行检索
线程实操
线程池创建
注意:方式有多种,你也可以使用jdk1.8版本的自带的线程池,我这里还是使用Executor的子类ExecutorService
/**
* 初始化SpringBean 工厂类
*/
@Component
@Configuration
public class BeanComponents {
/**
* 线程池初始化对象
* 根据自己的实际业务进行扩展,参数数据自行配置
* 我这里的环境就是,业务方法执行最高7条曲线,所以我设置为10个线程初始化,足够用
* @return
*/
@Bean
public ExecutorService executorService(){
return new ThreadPoolExecutor(5,//池中保持线程数
15,//最大线程数
60,//当线程数大于核心时,终止前多余空闲线程等待时间
TimeUnit.SECONDS,//时间单位为秒
new LinkedBlockingDeque<>(10),//池内队列最高10个线程
Executors.defaultThreadFactory(),//执行程序创建新线程使用默认工厂
new ThreadPoolExecutor.DiscardPolicy());//出现阻塞时使用处理程序
}
}
创建线程返回基类
何为基类?
这个就是说你要将每个线程执行完的返回结果放到线程池里面去。
注意;我发现SpringBoot在加载普通类时并没有提供IOC注入,通常我在注入某个API时总是NULL,
这里我提供了一种方法:{首先将当前类静态化属性,使用初始化方法将依赖API注入当前类即可使用}
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import org.tfcloud.energy.dto.IndexValueDto;
import org.tfcloud.energy.dto.MachineAnalysisDto;
import org.tfcloud.energy.service.impl.MongoEverServiceImpl;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.Callable;
//我这里选择实现Callable接口执行线程~
@Data
@SuppressWarnings("all")
@AllArgsConstructor
@Component
public class ThreadDtoUtils implements Callable<MachineAnalysisDto> {
@Autowired
private MongoEverServiceImpl mongoEverService;
public static ThreadDtoUtils threadDtoUtils;
/**
* 初始化当前类时即赋值-用于SpringBoot普通类注入对象为空
*/
@PostConstruct
public void inits(){
threadDtoUtils=this;
threadDtoUtils.mongoEverService=this.mongoEverService;
}
/**
* 指标名称
*/
private String paramName;
@Transient
private List<String> timeList;
@Transient
private String machineCode;
@Transient
private MongoTemplate mongoTemplateEnergy;
@Transient
private MongoTemplate mongoTemplateDye;
/**
* 机台存在多个指标名称-集合{指标名称|用量值}
*/
private List<IndexValueDto> indexValueDtoList;
public ThreadDtoUtils(){
}
public ThreadDtoUtils(String paramName,List<String> timeList,String machineCode, MongoTemplate mongoTemplateEnergy,MongoTemplate mongoTemplateDye){
this.paramName=paramName;
this.timeList=timeList;
this.machineCode=machineCode;
this.mongoTemplateEnergy=mongoTemplateEnergy;
this.mongoTemplateDye=mongoTemplateDye;
}
//核心方法,异步执行该方法进行业务处理,
@Override
public MachineAnalysisDto call() throws Exception {
System.out.println("*********线程执行"+Thread.currentThread().getName()+"执行");
MachineAnalysisDto machineAnalysisDto = threadDtoUtils.mongoEverService.
getMachineAnalysisDto(paramName, timeList, machineCode, mongoTemplateEnergy, mongoTemplateDye);
return machineAnalysisDto;
}
}
异步线程执行方法接收
我这里的业务是根据paramTypes.size()这个数字进行线程执行次数,如果是8次,那就是循环8次,
那么这8次执行就会分8个线程,每条线程互不相干,每执行完一个线程,就会添加至线程存储Future中
//线程结果存储
List<Future<?>> futures = new ArrayList<>(paramTypes.size());
for (int i = 0; i < paramTypes.size(); i++) {
ThreadDtoUtils threadDtoUtils = new ThreadDtoUtils(paramTypes.get(i), timeDiffs, machineCode, mongoTemplateEnergy, mongoTemplateDye);
//异步非阻塞执行异常处理
Future<MachineAnalysisDto> future = executorService.submit(threadDtoUtils);
futures.add(future);
}
//这里我就是将线程池中数据转换成我想要的数据,业务自行扩展即可
futures.stream().forEach(item -> {
try {
//转换类就是之前继承Callable的那个类
MachineAnalysisDto machineAnalysisDto = (MachineAnalysisDto) item.get();
//这里我是根据日期排了一个序,这个不用管~~
machineAnalysisDto.getIndexValueDtoList().sort((s1,s2) -> s1.getCurrDate().compareTo(s2.getCurrDate()));
//添加至我返回给前端展示的集合当中
machineAnalysisDtos.add(machineAnalysisDto);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
总结
至此我还是发现我的不足之处,平时写业务没问题,就是在处理一些特殊业务时平时的技术就难以攻克
平时还是要多注重一些核心技术点,例如~多线程,高并发,等都需要自己动手实践,举一反三用于项目中,提高执行效率。