多线程处理大量数据 java

项目场景:

简述项目相关背景:
例如:获取大量数据并处理,生成execl文件导出


问题描述:

5W条数据处理后生成execl文件需要6个小时,效率慢 APP 中接收数据代码:
@Override
        public void run() {
            bytes = mmInStream.read(buffer);
            mHandler.obtainMessage(READ_DATA, bytes, -1, buffer).sendToTarget();
        }

原因分析:

数据量太多


解决方案:

使用多线程批量处理数据,下面是线程类,直接复制即可

package com.wwhl.cms.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @param <H> 为被处理的数据类型
 * @param <T>返回数据类型
 */
public abstract class MultiThread<H,T>{
    private final ExecutorService exec; //线程池
    private final BlockingQueue<Future<T>> queue = new LinkedBlockingQueue<>();
    private final CountDownLatch startLock = new CountDownLatch(1); //启动门,当所有线程就绪时调用countDown
    private final CountDownLatch endLock; //结束门
    private final List<H> listData;//被处理的数据


    /**
     * @param list list.size()为多少个线程处理,list里面的H为被处理的数据
     */
    public MultiThread(List<H> list){
        if(list!=null&&list.size()>0){
            this.listData = list;
            exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //创建线程池,线程池共有nThread个线程
            endLock = new CountDownLatch(list.size());  //设置结束门计数器,当一个线程结束时调用countDown
        }else{
            listData = null;
            exec = null;
            endLock = null;
        }
    }

    /**
     *
     * @return 获取每个线程处理结速的数组
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public List<T> getResult() throws InterruptedException, ExecutionException{
        List<T> resultList = new ArrayList<>();
        if(listData!=null&&listData.size()>0){
            int nThread = listData.size(); //线程数量,可根据系统性能自定义线程数
            for(int i = 0; i < nThread; i++){
                H data = listData.get(i);
                Future<T> future = exec.submit(new Task(i,data){
                    @Override
                    public T execute(int currentThread,H data) {
                        return outExecute(currentThread,data);
                    }
                }); //将任务提交到线程池
                queue.add(future); //将Future实例添加至队列
            }
            startLock.countDown(); //所有任务添加完毕,启动门计数器减1,这时计数器为0,所有添加的任务开始执行
            endLock.await(); //主线程阻塞,直到所有线程执行完成
            for(Future<T> future : queue) {
                resultList.add(future.get());
            }
            exec.shutdown(); //关闭线程池
        }
        return resultList;
    }
    /**
     * 每一个线程执行的功能,需要调用者来实现
     * @param currentThread 线程号
     * @param data 每个线程被处理的数据
     * @return T返回对象
     */
    public abstract T outExecute(int currentThread,H data);

    /**
     * 线程类
     */
    private abstract class Task implements Callable<T>{
        private int currentThread;//当前线程号
        private H data;
        public Task(int currentThread,H data){
            this.currentThread=currentThread;
            this.data=data;
        }
        @Override
        public T call() throws Exception {
            startLock.await(); //线程启动后调用await,当前线程阻塞,只有启动门计数器为0时当前线程才会往下执行
            T t =null;
            try{
                t = execute(currentThread,data);
            }finally{
                endLock.countDown(); //线程执行完毕,结束门计数器减1
            }
            return t;
        }

        /**
         * 每一个线程执行的功能
         * @param currentThread 线程号
         * @param data 每个线程被处理的数据
         * @return T返回对象
         */
        public abstract T execute(int currentThread,H data);
    }
}

使用多线程批量处理数据使用场景:

 /**
     * 分割list集合
     *
     * @param dataList
     * @return
     */
    public List<Card> subList(List<Card> dataList) {
        List<Card> resultlist = new ArrayList<>();//存放批量数据处理的总结果集
        if (null != dataList && dataList.size() > 0) {
            int pointsDataLimit = 10;//限制条数 10条一批  
            Integer size = dataList.size();
            //判断是否有必要分批
            if (pointsDataLimit < size) {//大于10条
                int part = size / pointsDataLimit;//分批数
                for (int i = 0; i < part; i++) {
                    List<Card> listPage = dataList.subList(0, pointsDataLimit);  //10条数据
                    Integer start = cardlist.size();//10条数据在总结果集的开始下标
                    cardlist = testTime(listPage, resultlist );//返回拼接后的总结果集
                    Integer end = resultlist .size();//10条数据在总结果集的结束下标
                    for (i = start; i < end; i++) {
                   //对总数据集的10条数据进行业务处理
                    }
                    //剔除已经处理过的10条数据
                    dataList.subList(0, pointsDataLimit).clear();
                }
                if (!dataList.isEmpty()) {//小于10条
                    cardlist = testTime(dataList, cardlist);//处理最后的数据
                }
            } else {
            }
        }

        return resultlist ;
    }
 /**
     * 多线程处理批量数据
     *
     * @param splitList 处理数据
     * @param cardlist  处理后总数据
     *
     * @return
     */
    public List<Card> testTime(List<Card> splitList, List<Card> cardlistr) {
        List<Card> list = null;
        try {
            MultiThread<Card, Card> multiThread = new MultiThread<Card, Card>(splitList) {              
                @Override
                public Card outExecute(int currentThread, Card data) {
                //业务处理
                   /* String iccid = data.getIccid();
                    String allOrder = cardServerService.findAllOrder(iccid);
                    String allFlow = cardServerService.allFlowByiccid(iccid);
                    String allUseFlow = cardServerService.allUseFlowByiccid(iccid);
                    Card card = cardMapper.findByIccid(iccid);
                    String monthFlow = card.getMonthFlow();
                    data.setMonthFlow(monthFlow);
                    data.setAllOrder(allOrder);
                    data.setAllFlow(allFlow);
                    data.setAllUseFlow(allUseFlow);
                    return data;*/
                //业务处理end
                }
            };
            list = multiThread.getResult();//返回结果
            for (Card ccar : list) {
                cardlist.add(ccar);//批量数据遍历放入总结果
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cardlist;

    }

Card实体

/**
 * 卡实体类
 */
public class Card {

    /**
     * 主键id
     */
    private Long id;

    /**
     * 卡号
     */
    private String cardNum;
}

  • 4
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值