Java 使用线程池执行大数据量统计任务

最近需要对每周生成的日志表进行处理,并且输出结果到另一张表。日志表少的有300万,多有的有上千万条记录。因此打算用多线程来处理数据。在使用线程池时,几个注意点:

1、在入口的地方,直接新建一个线程为执行,然后返回结果,后续通过日志表来跟踪;

2、设置独立的线程名规则,区分自动生成的线程名;

3、直接使用ThreadPoolExecutor,而不是借用Executors类生成;

4、利用Future的阻塞特性来控制全部线程执行结束的时间点;

5、考虑是否有必要增加中断执行的机制;

6、考虑能合成批量操作的地方尽量合成批量操作。

代码参考:

        //1.计算线程数
        int threadNum = totalCount / StatConstant.SPLIT_NUM;
        if (threadNum * StatConstant.SPLIT_NUM < totalCount) {
            threadNum++;
        }
        //2.发起线程
        List<Future<Integer>> futureList = new ArrayList<>();
        ThreadFactory threadFactory = new ThreadFactoryBuilder()
                .setNameFormat("LogHandlerThread-%d")
                .build();
        ExecutorService executorService = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(threadNum), threadFactory);
        for (int i = 0; i < threadNum; i++) {
            int begin = i * StatConstant.SPLIT_NUM;
            int end = (i + 1) * StatConstant.SPLIT_NUM;
            if (i == threadNum - 1) {
                end = totalCount;
            }
            Future<Integer> future = executorService.submit(new LogHandlerThread(begin, end, weekNo, applicationContext));
            futureList.add(future);
        }
        //3.记录线程结果
        boolean finalResult = true;
        for (int i = 0; i < futureList.size(); i++) {
            try {
                Future<Integer> future = futureList.get(i);
                Integer result = future.get();
                handleCount += ((result == null) ? 0 : result);
            } catch (Exception e) {
                weekLog.setMessage(weekLog.getMessage() + "###" + "(ThreadNum=" + i + ")" + e.getMessage());
                finalResult = false;
            }
        }
        executorService.shutdown();
        //4.执行其他任务...
     public class LogHandlerThread implements Callable<Integer> {
        public LogHandlerThread(Integer begin, Integer end, String weekNo, ApplicationContext applicationContext) {
          //初始..
        }
        @Override
        public Integer call() {
          //执行..
        }
     }

期间还碰上,死锁的问题(org.springframework.dao.DeadlockLoserDataAccessException: PreparedStatementCallback; SQL [INSERT IGNORE INTO tb(...) VALUES (..)]; Deadlock found when trying to get lock; try restarting transaction;),本来想通过批量初始来提高性能,但是表在更新的时候,如果是锁同样的行记录,确实容易出现死锁,没有太好的办法,说明业务逻辑上可能需要适当的调整来规避这种多线程冲突的情况,优先通过优化设计来解决冲突。


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值