JAVA线程异步并发执行


先感谢微信一个老哥 薛华隆老哥的指导~~

多线程简述

我的理解就是解决一个请求在执行业务时能够并发执行,将本该一个人做的事情分别交给几个人做,具体详解请自行检索

线程实操

线程池创建

注意:方式有多种,你也可以使用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();
			}
		});

总结

至此我还是发现我的不足之处,平时写业务没问题,就是在处理一些特殊业务时平时的技术就难以攻克
平时还是要多注重一些核心技术点,例如~多线程,高并发,等都需要自己动手实践,举一反三用于项目中,提高执行效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章