FutureTask
关于 FutureTask 简介请移步 FutureTask详解
这里只给出业务应用场景方案:
- 创建自定义业务执行器,实现 Callable 接口
@Slf4j
public class BusinessExecutor implements Callable {
// 业务mapper
private XxxxMapper xxxxMapper;
private List list;
public BusinessExecutor() {
}
public BusinessExecutor(List list) {
// Spring容器获取mapper
xxxxMapper= (XxxxMapper)ApplicationContextGetBeanHelper.getBean("xxxxMapper");
this.list = list;
}
@Override
public List call() throws Exception {
if(CollectionUtils.isEmpty(list)){
return new ArrayList();
}
List<Map> result = new ArrayList<>();
// 模拟业务
for(int i = 0;i<list.size();i++){
log.info(Thread.currentThread().getName()+" - "+list.get(i));
Map map = new HashMap<>();
map.put("name", Thread.currentThread().getName());
map.put("value",list.get(i));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
result.add(map);
}
return result;
}
}
- 抽取多线程业务公共方法
/**
* 多线程并发处理业务类: 可获取子线程返回结果
*/
@Slf4j
public class ExecutorService {
/**
* 并发处理业务
* @param threadNum 线程大小
* @param list 目标集合
* @param t 业务处理类
*
*/
public List invokeTask(Integer threadNum, List list, Class<?> t) {
try {
int merchant = list.size()/threadNum;
int remainder = list.size()%threadNum;
if(merchant<threadNum){
if(remainder == 0){
threadNum = merchant;
}else{
threadNum = merchant+1;
}
}
log.info("除数(merchant):{} -- 余数(remainder):{}",merchant,remainder);
// 创建线程池
java.util.concurrent.ExecutorService pushPool = new ThreadPoolExecutor(
threadNum,
threadNum * 2,
30,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5000),
new ThreadPoolExecutor.DiscardPolicy()
);
List result = Collections.synchronizedList(new ArrayList<>());
log.info("【并发处理业务】 -- 创建线程池,线程数量:{}",threadNum);
// 子线程集合
List<FutureTask> tasks = new ArrayList<>();
for(int i = 0;i<threadNum;i++) {
List<Object> subsetList = new ArrayList<>();
int fromIndex = i * merchant;
int toIndex = i < (threadNum - 1) ? ((i + 1) * merchant) : list.size();
log.info("循环截取原始任务列表:fromIndex:{} -- toIndex:{}", fromIndex, toIndex);
subsetList = list.subList(fromIndex, toIndex);
List<Object> finalSubsetList = subsetList;
// 通过类名获取相应的Class对象
Class executorClass = Class.forName(t.getName());
// 通过获取回来的Class对象,调用getConstructor,参数就是我们要初始化的类的有参构造
// 方法的参数泛型,获取到有参构造方法
Constructor constructor = executorClass.getConstructor(List.class);
//通过有参构造方法,调用创建对象的参数,得到了object对象
// 要转换成对应类型的对象,强转即可
// 定义多种类型的话,可以写公共接口或者抽象类,用工厂设计模式、中介者设计模式
Object obj = constructor.newInstance(finalSubsetList);
Callable executor = null;
if(ObjectUtil.isNotNull(obj)){
executor = (Callable) obj;
}
// FutureTask 可以获取线程结果集
FutureTask<List> task = new FutureTask<>(executor);
pushPool.execute(task);
tasks.add(task);
}
// 组装子线程数据并返回
tasks.forEach(
task->{
try {
// 获取子线程结果集
Object o = task.get();
result.addAll((List)o);
}catch (Exception e){
task.cancel(true);
}
}
);
return result;
}catch (Exception e){
throw new RuntimeException(e.getMessage());
}
}
}
- 调用测试
@Slf4j
public class ExecutorTest {
public static void main(String[] args) {
List<String> a = new ArrayList<>();
for(int i=0;i<100;i++){
a.add(String.valueOf(i+1));
}
// 并发
Long start = System.currentTimeMillis();
ExecutorService myExecutorService = new ExecutorService();
List list = myExecutorService.invokeTask(3, a,BusinessExecutor.class);
Long end = System.currentTimeMillis();
System.out.println("结果集数量:"+list.size()+ ",并发处理耗时:"+(end-start));
// 普通
Long start2 = System.currentTimeMillis();
List<Map> result = new ArrayList<>();
// 模拟业务
for(int i = 0;i<a.size();i++){
//log.info(Thread.currentThread().getName()+" - "+a.get(i));
Map map = new HashMap<>();
map.put("name", Thread.currentThread().getName());
map.put("value",a.get(i));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
result.add(map);
}
Long end2 = System.currentTimeMillis();
System.out.println("结果集数量:"+result.size()+ ",通处理耗时:"+(end2-start2));
}
}
- 结果比较
工具类:
@Component
public class ApplicationContextGetBeanHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static Object getBean(String className) throws BeansException, IllegalArgumentException {
if (className == null || className.length() <= 0) {
throw new IllegalArgumentException("className为空");
}
String beanName = null;
if (className.length() > 1) {
beanName = className.substring(0, 1).toLowerCase() + className.substring(1);
} else {
beanName = className.toLowerCase();
}
return applicationContext != null ? applicationContext.getBean(beanName) : null;
}
}