一、线程池的概念
创建Java线程需要给线程分配堆栈内存以及初始化内存,还需要进行系统调用,频繁地创建和销毁线程会大大降低系统的运行效率,采用线程池来管理线程有以下好处:
- 提升性能:线程池能独立负责线程的创建、维护和分配
- 线程管理:每个Java线程池会保持一些基本的线程统计信息,对线程进行有效管理
二、线程池的应用场景
传输文件
签到和秒杀
爬虫
三、线程池的基本使用
controller层
package tech.niua.admin.multithreading.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.niua.admin.multithreading.service.ThreadService;
import java.util.List;
@RestController
@RequestMapping("/thread")
public class MultiThreadController {
@Autowired
private ThreadService threadService;
@GetMapping("/testThreadData")
public List testThreadData(){
System.out.println(threadService.getAllResult()+"线程返回数据");
return threadService.getAllResult();
}
}
service层(这里在service层写了一个方法的封装,当然也可以在service写业务)
package tech.niua.admin.multithreading.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.niua.admin.multithreading.MultiThreadQueryUtil;
import tech.niua.admin.multithreading.service.ThreadService;
import java.util.List;
@Service
public class ThreadServiceImpl implements ThreadService {
@Autowired
private MultiThreadQueryUtil multiThreadQueryUtil;
@Override
public List getAllResult() {
return multiThreadQueryUtil.getMultiCombineResult();
}
}
MultiThreadQueryUtil类
我这里的数据一共11条
package tech.niua.admin.multithreading;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.niua.admin.multithreading.mapper.WorkflowTaskMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@Service
public class MultiThreadQueryUtil {
@Autowired
private WorkflowTaskMapper workflowTaskMapper;
/**
* 获取多线程结果并进行结果合并
* @return
*/
public List<List> getMultiCombineResult() {
//开始时间
long start = System.currentTimeMillis();
//返回结果
List<List> result = new ArrayList<>();
//查询数据库总数量
int count = workflowTaskMapper.selectCountAll();
//这里对数据库中的数据进行了一个分组,每组交给不同的线程,每5个为一组
//当然这里的逻辑都可以根据自己相应的业务进行更改
Map<String,String> splitMap = ExcelLocalUtils.getSplitMap(count,5);
//Callable用于产生结果
List<Callable<List>> tasks = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
//不同的线程用户处理不同分段的数据量,这样就达到了平均分摊查询数据的压力
System.out.println(splitMap.get(String.valueOf(i)));
String[] nums = splitMap.get(String.valueOf(i)).split(":");
int startNum = Integer.valueOf(nums[0]);
int endNum = Integer.valueOf(nums[1]);
//将相应的任务放到Callable
Callable<List> qfe = new ThreadQuery(startNum, endNum-startNum+1);
tasks.add(qfe);
}
try{
//定义固定长度的线程池 防止线程过多,5就够用了
ExecutorService executorService = Executors.newFixedThreadPool(5);
//Future用于一并获取结果
List<Future<List>> futures=executorService.invokeAll(tasks);
//处理线程返回结果
if(futures!=null&&futures.size() > 0){
for (Future<List> future:futures){
result.addAll(future.get());
}
}
//关闭线程池,一定不能忘记
executorService.shutdown();
}catch (Exception e){
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("线程查询数据用时:"+(end-start)+"ms");
return result;
}
}
ThreadQuery 类
package tech.niua.admin.multithreading;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
public class ThreadQuery implements Callable<List> {
// public static SpringContextUtil springContextUtil = new SpringContextUtil();
private int start;
private int end;
//每个线程查询出来的数据集合
private List datas;
public ThreadQuery(int start,int end) {
//这里可以实现相应的业务代码
}
//返回数据给Future
@Override
public List call() throws Exception {
return datas;
}
}