ThreadPoolExecutor实现多线程并发并获得返回值(优雅简洁方式)

前言
数据库信息查询是大家最经常见到的工作问题。一般是单线程顺序查询,这样查询总时间是所有查询时间之和,消耗时间较长。如果采用多线程并行查询,则时间变成单个功能查询时间最长的。时间大大缩短。依据阿里开发规范,要重写ThreadPoolExecutor线程池,提高可控性。数据库查询还需要活动线程执行完的返回值,这样就不但要重写ThreadPoolExecutor,还得重写CallAble还获得返回值(RunAble不支持获得返回值)。下面给大家介绍一种优雅简洁实现上面功能的例子。
场景:实现多线程并发并获得返回值
代码:
因为大家contorller和dao层都很熟悉了,我这也不涉及他们的改变,就先省略。直接写需要改变的serviceImpl。
serviceImpl层:

package com.asiainfo.cem.uaa.service;

import com.asiainfo.cem.common.util.ParallelUtil;
import com.asiainfo.cem.common.util.ParallelUtil.ParallelJob;
import com.asiainfo.cem.uaa.common.UaaConstants;
import com.asiainfo.cem.uaa.domain.LoginUserDTO;
import com.asiainfo.cem.uaa.domain.SysUser;
import com.asiainfo.cem.uaa.dao.SysPermissionDao;
import com.asiainfo.cem.uaa.dao.SysRoleDao;
import com.asiainfo.cem.uaa.dao.SysUserDao;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 *@program: cem
 *@description:
 *@author: houzf
 */
@Service
public class UserServiceDetail implements UserDetailsService {

  @Autowired
  private SysUserDao sysUserDao;
  @Autowired
  private SysRoleDao sysRoleDao;
  @Autowired
  private SysPermissionDao sysPermissionDao;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    SysUser userDO = sysUserDao.findByUsername(username);
    if (userDO == null) {
      throw new UsernameNotFoundException(MessageFormat.format("{0} is empty.", username));
    }

    ParallelJob<Set<String>> getRoleCodeByUserNameJob = new ParallelJob<Set<String>>()
        .setFunction(() -> sysRoleDao.getRoleCodeByUserName(username));

    ParallelJob<Set<String>> getPermissionByUserNameJob = new ParallelJob<Set<String>>()
        .setFunction(() -> sysPermissionDao.getPermissionByUserName(username));

    ParallelJob<Set<String>> getPermissionCodeByUserNameJob = new ParallelJob<Set<String>>()
        .setFunction(() -> sysPermissionDao.getPermissionCodeByUserName(username));
    ParallelUtil.execute(getRoleCodeByUserNameJob, getPermissionByUserNameJob,getPermissionCodeByUserNameJob);

    Set<String>roles=getRoleCodeByUserNameJob.getResutl();
    HashMap map=new HashMap(roles.size());
 if (roles.size()!=0){
    for (String roleCode:roles){
      List<String>permissionCodeList=new ArrayList<>();
      if(UaaConstants.ADMIN.equals(roleCode)||UaaConstants.SUPADMIN.equals(roleCode)){
        permissionCodeList.add(UaaConstants.ALL_PERMISSION);
      }else {
        permissionCodeList = sysPermissionDao.getPermissionByRoleCode(roleCode);
      }
     map.put(roleCode,permissionCodeList);
    }
  }
    LoginUserDTO loginUserDTO = new LoginUserDTO()
        .setPermissionCodes(getPermissionCodeByUserNameJob.getResutl())
        .setRoles(roles)
        .setRoleAndPermissions(map)
        .setUser(userDO);

    return loginUserDTO;
  }
}

这个是并发任务关键工具类,主要是用泛型和线程池,优雅简洁的解决问题。可以通用于整个项目。
Util:

package com.asiainfo.cem.common.util;

import java.util.Arrays;
import java.util.function.Supplier;
import lombok.Data;
import lombok.NonNull;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

/**
 *@program: cem-service
 *@description: 并行任务工具类
 *@author: houzf
 */
@Slf4j
public class ParallelUtil {


  @FunctionalInterface
  public interface ParallelFunction<T> extends Supplier<T> {

  }

  @Data
  @Accessors(chain = true)
  public static class ParallelJob<T> {

    private ParallelFunction<T> function;
    private T resutl;
  }

  public static void execute(@NonNull ParallelJob... jobs) {
    Arrays.stream(jobs).parallel().forEach(job ->
        job.setResutl(job.getFunction().get())
    );
  }

}

再举一个serviceImpl例子

package com.asiainfo.cem.governmental.service.impl;

import com.asiainfo.cem.common.domain.CommonResult;
import com.asiainfo.cem.common.util.ParallelUtil;
import com.asiainfo.cem.common.utils.GetPointSetUtil;
import com.asiainfo.cem.common.utils.PageUtil;
import com.asiainfo.cem.common.utils.StringUtil;
import com.asiainfo.cem.governmental.dao.CemGovernmentalDataMapper;
import com.asiainfo.cem.governmental.domain.dto.GovernmentalScoreInfo;
import com.asiainfo.cem.governmental.domain.query.GovernmentalQueryAllScoreParam;
import com.asiainfo.cem.governmental.domain.query.GovernmentalQueryAllScoreCountParam;
import com.asiainfo.cem.governmental.domain.vo.GovernmentalQueryAllScoreVo;
import com.asiainfo.cem.governmental.service.interfaces.ICemGovernmentalServiceCSV;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.sql.Timestamp;
import java.util.concurrent.*;

@Service
@Transactional
@Slf4j(topic = "Governmental-PERCEPTION")
public class ICemGovernmentalServiceCSVImpl implements ICemGovernmentalServiceCSV {

    private static final Logger logger = LoggerFactory.getLogger("GOVERNMENTAL_THREAD_TASK");

    @Autowired
    private CemGovernmentalDataMapper cemGovermentalDaoMapper;

    private static ExecutorService threadPool;

    /**
     * @param params
     * @description:查询政企客户满意度相关评分
     * @return: {@link CommonResult}
     * @author houzf
     */
    @Override
    public CommonResult queryAllPerceptionScore(GovernmentalQueryAllScoreVo params) {

        Integer pageNum = 1;
        if (!StringUtil.isBlank(params.getPageNum())) {
            pageNum = Integer.valueOf(params.getPageNum());
        }
        Integer pageSize = Integer.valueOf(params.getPageSize());
        String order = params.getOrder();
        String p1 = params.getP1();
        String p2 = params.getP2();
        String p3 = params.getP3();
        String p4 = params.getP4();
        Timestamp startTime = Timestamp.valueOf(params.getStartTime() + " 00:00:00");
        Timestamp endTime = Timestamp.valueOf(params.getStartTime() + " 23:59:59");

        Integer pageIndex = (pageNum - 1) * pageSize;

        String[] points = GetPointSetUtil.lngLatSwap(new String[]{p1, p2, p3, p4});
        double[] pointSetScope = GetPointSetUtil.
                getPointSetScope(new String[]{points[0], points[1], points[2], points[3]});
        double maxLongitude = pointSetScope[0];
        double minLongitude = pointSetScope[1];
        double maxLatitude = pointSetScope[2];
        double minLatitude = pointSetScope[3];

        GovernmentalQueryAllScoreCountParam perceptionQueryAllScoreCountParam =
                GovernmentalQueryAllScoreCountParam.builder()
                        .maxLongitude(maxLongitude)
                        .minLongitude(minLongitude)
                        .maxLatitude(maxLatitude)
                        .minLatitude(minLatitude)
                        .startTime(startTime)
                        .endTime(endTime)
                        .build();

        GovernmentalQueryAllScoreParam perceptionQueryAllScoreParam =
                GovernmentalQueryAllScoreParam.builder()
                        .maxLongitude(maxLongitude)
                        .minLongitude(minLongitude)
                        .maxLatitude(maxLatitude)
                        .minLatitude(minLatitude)
                        .startTime(startTime)
                        .endTime(endTime)
                        .pageSize(pageSize)
                        .pageIndex(pageIndex)
                        .order(order)
                        .build();

        //并行查询
        ParallelUtil.ParallelJob<Integer> total
                = new ParallelUtil.ParallelJob<Integer>().setFunction(() ->
                    cemGovermentalDaoMapper.getQueryAllPerceptionScoreListCount(perceptionQueryAllScoreCountParam));

        ParallelUtil.ParallelJob<List<GovernmentalScoreInfo>> dataList
                = new ParallelUtil.ParallelJob<List<GovernmentalScoreInfo>>().setFunction(() ->
                    cemGovermentalDaoMapper.queryAllPerceptionScore(perceptionQueryAllScoreParam));
        ParallelUtil.execute(total, dataList);           

        PageUtil<GovernmentalScoreInfo> pageUtil = new PageUtil<>();
        pageUtil.setPageNum(pageNum);
        pageUtil.setPageSize(pageSize);
        pageUtil.setTotal(Integer.valueOf(total.getResutl()));
        pageUtil.setData(dataList.getResutl());
        pageUtil.getPageCount();
        pageUtil.setCurrentTime(System.currentTimeMillis());
        return CommonResult.ok(pageUtil);
    }

}

主要就是看“//并行查询 ”下面一块。可以用任意类型的返回值,如Integer或者List。
如果帮助到了您,麻烦关注,点赞,收藏,三连。
您的肯定,是我的动力。祝中华民族早日复兴!谢谢大家。
؏؏☝ᖗ乛◡乛ᖘ☝؏؏

猜你喜欢

转载自blog.csdn.net/weixin_39434182/article/details/104875696