项目中哪里用到了多线程?

    嗯,这确实是一个比较经典的话题。以前听到多线程基本上就已经吓得尿裤子了,但是! 敲黑板了啊 画重点了啊。就在这个月我自己动手写出来了人生中第一个多线程的案例,并且完美解决了业务需要问题。将几百万的数据从一个表取出来 经过处理和再添加到另个表中 。那么我们来撩一撩这个业务的前世今生!

  之前已经写过了定时任务的数据压缩 但是那只是压缩一天的,那么从最开始上线到现在会有几个月的数据没有进行压缩,因此最开始我想的是将之前所有天数的数据循环进行压缩,但是这又有一个问题,压缩每一天的数据都会需要几十秒的时间,我要同时压缩几个月的,那将是一段很漫长的过程。所以这个时候,我想到了用多线程的方式执行压缩任务。开10个线程分别去压缩一天任务,然后通过循环将天数进行累加,交给多线程去执行,最后三个月的压缩完毕之后,仅仅用了30秒不到。

上代码:

@Service
@Transactional
public class TenminuteTaskDataCompressionService {

    private final Logger log = LoggerFactory.getLogger(TenminuteTaskDataCompressionService.class);

    private final TenminuteTaskDataCompressionRepository tenminuteTaskDataCompressionRepository;

    @Autowired
    TenminuteTaskRepository tenminuteTaskRepository;

    private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 2000, TimeUnit.MILLISECONDS,
        new LinkedBlockingDeque(1000));

    public TenminuteTaskDataCompressionService(TenminuteTaskDataCompressionRepository tenminuteTaskDataCompressionRepository) {
        this.tenminuteTaskDataCompressionRepository = tenminuteTaskDataCompressionRepository;
    }
public int excuteDataCompressionByOperateDate(String operateDate,String deleteFlag) {
        log.debug("the request param is :{}",operateDate,deleteFlag);
        //传1异常压缩 先删压缩表当天数据再压缩
        if("1".equals(deleteFlag)){
            tenminuteTaskDataCompressionRepository.deleteAllByOperateDate(operateDate);
        }
        // 1.取出前一天的所有数据
        List allByOprateDate = tenminuteTaskRepository.findAllByOprateDate(operateDate);
        log.debug("总共的数据条数为"+allByOprateDate.size());
        if(allByOprateDate.isEmpty() && allByOprateDate.size() == 0){
            return 0;
        }
        List compressionList = null;
        try {
 log.debug("开始压缩数据,目标天数为:{}",operateDate);
            // 2.封装数据
            compressionList = createCompressionList(allByOprateDate);
            // 3.将压缩的数据 存到压缩表
            tenminuteTaskDataCompressionRepository.save(compressionList);
            log.debug("已将数据存入压缩表,条数为"+compressionList.size());
            // 4.删除原表指定天数数据
            tenminuteTaskRepository.deleteAllByOperateDate(operateDate);
        }catch (Exception e){
            log.error("压缩数据发生异常{}",e.getMessage());
        }
        return 1;
    }
/**
     * 将前一天的数据进行转化为新的实体集合
     *
     * @param allByOprateDate
     * @return
     */
    public List createCompressionList(List allByOprateDate) {
        Map> collect = allByOprateDate.stream().collect(Collectors.groupingBy(TenminuteTask::getDeviceUuid));
        List listvo = Lists.newArrayList();
        collect.forEach((k, v) -> {
            TenminuteTaskDataCompression allentity = new TenminuteTaskDataCompression();
            allentity.setUuid(UUIDUtil.getAscId());
            allentity.setDeviceUuid(k);
            allentity.setTenantUuid(v.get(0).getTenantUuid());
            allentity.setOperateDate(v.get(0).getOperateDate());
            allentity.setCreatedBy("system");
            allentity.setLastModifiedBy("system");
Map> integerListMap = v.stream().collect(Collectors.groupingBy(TenminuteTask::getOperateHour));
            Map> stringMapList= new HashMap<>();
            integerListMap.forEach((hour,tenminuteTasks)->{
                // 将这个list转换成string类型的数组集合
                List stringList = new ArrayList<>();
                // 将集合数据转成数组
                tenminuteTasks.forEach(tenminuteTask -> {
                    String[] aa= new String[12];
                    //下标为0 存在线时间
                    aa[0]=tenminuteTask.getOnTime().toString();
                    //下标为1 存作业时间
                    aa[1]=tenminuteTask.getOperationTime().toString();
                    //下标为2 存待机时间
                    aa[2]=tenminuteTask.getStandByTime().toString();
                    //下标为3 存停机时间
                    aa[3]=tenminuteTask.getDownTime().toString();
//下标为4 存离线时间
                    aa[4]=tenminuteTask.getOfflineTie().toString();
                    //下标为5 存能耗
                    aa[5]=tenminuteTask.getEnergy().toString();
                    //下标为6 存电价
                    aa[6]=tenminuteTask.getElectPrice().toString();
                    //下标为7 存成本
                    aa[7]=tenminuteTask.getCostPrice().toString();
                    //下标为8 存操作时间
                    aa[8]=tenminuteTask.getOperateHour().toString();
                    //下标为9 存操作分钟
                    aa[9]=tenminuteTask.getOperateMinute().toString();
                    //下标为10 存最小能耗
                    aa[10]=tenminuteTask.getMinusEnergy().toString();
                    //下标为11 存完整时间
                    aa[11]=tenminuteTask.getOperateFullDate();
stringList.add(aa);
                });
                stringMapList.put(hour,stringList);
                //然后遍历map1的时候 把这些值put到map2中
            });

            Gson gson = new Gson();
            String json = gson.toJson(stringMapList);
            allentity.setCompressionJsonInfo(json);
            listvo.add(allentity);
        });
        return listvo;
    }
/**
     * 批量压缩十分钟数据接口 应该是使用一次 以后的数据由定时任务压缩即可
     * @param startDate
     * @param endDate
     */
    public void excuteBetchDataCompression(String startDate, String endDate) {
       DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate s = LocalDate.parse(startDate);
        LocalDate e= LocalDate.parse(endDate);
        //相差天数设置成活的
        long num=e.toEpochDay()-s.toEpochDay();
        int number=(int) num;

        for (int i = 0; i < number; i++) {
            if (endDate.equals(startDate)) {
                break;
            }
            executor.execute(new TenminuteCompressionTask(i, startDate,this));
            LocalDate parse = LocalDate.parse(startDate);
            startDate = parse.plusDays(1).format(dateTimeFormatter);
        }
        //显式调用之后 线程池就关闭了 再调用接口的话就无法使用了 得重新启动 如果不显式关闭的话 线程会一直存在 jvm不会退出 直到新的请求进来
        //executor.shutdown();
    }
class TenminuteCompressionTask implements Runnable {
        private int taskNum;
        private String startDate;
        TenminuteTaskDataCompressionService tenminuteTaskDataCompressionService;

        public TenminuteCompressionTask(int taskNum, String startDate,TenminuteTaskDataCompressionService tenminuteTaskDataCompressionService) {
            this.taskNum = taskNum;
            this.startDate = startDate;
            this.tenminuteTaskDataCompressionService =tenminuteTaskDataCompressionService;
        }

        @Override
        public void run() {
            log.debug("正在执行task " + taskNum+"当前线程为"+Thread.currentThread().getName()+"  正在压缩" + startDate + "的数据。。。。");
            tenminuteTaskDataCompressionService.excuteDataCompressionByOperateDate(startDate,"0");
            log.debug(startDate+"的数据压缩完毕");
        }
    }
}

   通过线程池的方式去创建线程,减少创建和销毁线程的资源消耗!

你可能感兴趣的:(项目中哪里用到了多线程?)