线程配合队列使用
在这之前写过一篇线程池的但其中一些并没有介绍清楚,在手打几遍后有了更深的理解,故此记录下
在项目中有个功能模块需要本地生成pdf并且上传至云服务器,这个时候用线程处理比较合理,并且之前也用过线程池并且当前场景也适合,所以最后决定使用线程池来完成。
首先需要明白我们要把需要的值组装成对象,再把对象扔到队列当中,接着去定义一个线程池然后遍历队列取值去做业务逻辑处理,最后启动线程整个过程就结束了。
通过构造方法塞值
ThreadPoolUtil.CreatePdfTask createPdfTask= new ThreadPoolUtil.CreatePdfTask(carsinfo.getId(),qualityApi);
数据组装对象(线程池类的内部类)
创建阻塞队列;创建线程池
具体线程类代码
import com.aicarsqc.business.util.ReduceImgUtil;
import com.aicarsqc.business.util.SftpUploadUtil;
import com.jcraft.jsch.SftpException;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component
public class ThreadPoolUtil {
@Resource
private BizQualitysummerServiceImpl bizQualitysummerService;
@Resource
private IBizCarsinfoService carsinfoService;
@Autowired
private TransactionTemplate transactionTemplate;
private ArrayBlockingQueue<ThreadPoolUtil.CreatePdfTask> arrayBlockingQueue = new ArrayBlockingQueue(1000);
// 创建一个大小为8的固定线程池,可以按照CPU的核数初步判定,如果CPU密集性任务则创建N+1个,如果是IO密集型任务则创建2N+1个,其中N即CPU的核数
private final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(8);
private Thread consumerThread = null;
private ThreadPoolUtil(){
consumerThread= new Thread(){
@SneakyThrows
@Override
public void run() {
while (true){
ThreadPoolUtil.CreatePdfTask task = arrayBlockingQueue.poll(3, TimeUnit.SECONDS);
if(task==null){
continue;
}
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//上传pdf
String path = null;
Boolean generateSucces = false;
//尝试生成三次报告
for (int i = 0; i < 3 && !generateSucces ; i++){
try{
path = bizQualitysummerService.exportPDF(task.carsinfoId);
}catch (Exception exception){
//如果有异常,重新生成
bizQualitysummerService.monitorLogger.info("生成PDF失败:"+task.qualityApi.toString());
continue;
}
generateSucces = true;
}
BizCarsinfo carsinfoupdate = new BizCarsinfo();
carsinfoupdate.setId(task.carsinfoId);
carsinfoupdate.setCiQualitystatus(generateSucces?2:3);
carsinfoService.updateById(carsinfoupdate);
bizQualitysummerService.sendPDF(path);
}
});
}
}
};
consumerThread.start();
}
@Data
public static class CreatePdfTask{
private String carsinfoId;
private QualityApi qualityApi;
public CreatePdfTask (String carsinfoId,QualityApi qualityApi){
this.carsinfoId=carsinfoId;
this.qualityApi=qualityApi;
}
}
public void putTask(ThreadPoolUtil.CreatePdfTask pdfTask){
try {
this.arrayBlockingQueue.put(pdfTask);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
接下来就是把队列放到线程池里然后启动线程
通过依赖注入的方式在项目启动的时候就启动线程