万能多线程处理业务并获取子线程结果集

FutureTask

关于 FutureTask 简介请移步 FutureTask详解

这里只给出业务应用场景方案:

  1. 创建自定义业务执行器,实现 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;
    }
}
  1. 抽取多线程业务公共方法
/**
 * 多线程并发处理业务类: 可获取子线程返回结果
 */
@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());
        }
    }
}
  1. 调用测试
@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));
    }
}

  1. 结果比较
    在这里插入图片描述
    工具类:
@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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值