spring boot项目中线程池/多线程的使用

背景:我们有一个需求是测试定时任务执行器中要调用的地址的连通性,要求是把数据库中现在所有的执行器的url都测试通不通,并返回结果。连通性测试超时时间为2000ms(2s),所以几百个url的连通性耗时就比较长。需要用多线程处理。

下面直接上代码

未修改前的老代码,执行数据异常缓慢,无法响应结果

public BeeResponseEntity urlConnectTestALL() {
        //1.从数据库查询所有执行器
        List<SchJobExecute> schJobExecutes = executeDaoService.selectAllNoCondition();
        if (schJobExecutes == null || schJobExecutes.isEmpty()){
            return BeeResponseEntity.failed(ErrorCodeEnum.EXEC_ADD_UNKNOWN_ERROR);
        }
        //2.遍历,筛选出url不通的执行器
        List<SchJobExecute> disConnectExecuteList = schJobExecutes.stream()
                .filter(schJobExecute -> !StringUtils.isEmpty(schJobExecute.getReqUrl()))
                .filter(schJobExecute -> !NetConnectUtils.telnetUtil(schJobExecute.getReqUrl()))
                .collect(Collectors.toList());
       
        LOGGER.info("分行域名不通清单:{}",disConnectExecuteList);
        return BeeResponseEntity.success(disConnectExecuteList);
    }

修改后的代码

public class SchJobExecuteTask implements Callable<JSONObject> {
    private final SchJobExecute schJobExecute;
    @Autowired
    private SchJobExecuteDaoService executeDaoService;

    public SchJobExecuteTask(SchJobExecute schJobExecute) {
        this.schJobExecute = schJobExecute;
    }

    @Override
    public JSONObject call() {
        // ip端口连通性测试
        boolean telnet = NetConnectUtils.telnetUtil(new ExeDomainReqDTO(schJobExecute.getReqUrl()));
        if (!telnet) {
            return schJobExecuteToJSON(schJobExecute);
        }
        return null;
    }

    private JSONObject schJobExecuteToJSON(SchJobExecute schJobExecute) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("执行器Code", schJobExecute.getExeCode());
        jsonObject.put("请求地址", schJobExecute.getReqUrl());
        jsonObject.put("渠道号", schJobExecute.getBranchNo());
        jsonObject.put("创建人", schJobExecute.getCreNam());
        jsonObject.put("创建用户ID", schJobExecute.getCreNbr());
        return jsonObject;
    }
}
private final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNamePrefix("消息处理统一调度线程").build();
    private final ExecutorService executorService = new ThreadPoolExecutor(50, 60, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingDeque<>(2048), threadFactory, new ThreadPoolExecutor.AbortPolicy());
            
@Override
    public BeeResponseEntity urlConnectTestALL() {
        // 从数据库查询所有执行器
        List<SchJobExecute> schJobExecutes = executeDaoService.selectAllNoCondition();

        try {
            // 提交每个schJobExecute对象的处理任务到线程池,并收集结果
            List<Future<JSONObject>> futures = executorService.invokeAll(
                    schJobExecutes.stream()
                            .filter(schJobExecute -> !StringUtils.isEmpty(schJobExecute.getReqUrl()))
                            .map(SchJobExecuteTask::new)
                            .collect(Collectors.toList())
            );

            // 处理线程池执行结果
            List<JSONObject> disConnectExecuteList = new ArrayList<>();
            for (Future<JSONObject> future : futures) {
                // 获取任务执行结果
                JSONObject result = future.get();
                if (result != null) {
                    disConnectExecuteList.add(result);
                }
            }
           LOGGER.info("连不通的执行器数量:{}", disConnectExecuteList.size());
            return BeeResponseEntity.success(disConnectExecuteList);
        } catch (Exception e) {
            LOGGER.error("连通性测试异常:", e);
            return BeeResponseEntity.failed(ErrorCodeEnum.SYSTEM_ERROR, "连通性测试异常");
        } finally {
            // 关闭线程池
            executorService.shutdown();
        }
    }

连通性测试工具类

public class NetConnectUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(NetConnectUtils.class);
    public final static Integer DEFAULT_PORT = 80;

    public final static Integer DEFAULT_TIMEOUT = 2000;

    public final static String REGEX_RULE = "((([a-zA-Z0-9-]+)(\\.[a-zA-Z0-9-]+)+)|localhost)(:[0-9]+)?";
    public final static String REGEX_SPLIT = ":";

    public String getExecuteFlag(String str) {
        return str;
    }


    /**
     * 判断url地址中的域名网络是否通畅
     *
     * @param dto
     * @return
     */
    public static boolean telnetUtil(ExeDomainReqDTO dto) {
        ExeDomainDTO dtoNew = createExeDomainDTObyString(dto);
        if (null == dtoNew) {
            return false;
        }
        boolean isConnected = false;
        Socket socket = new Socket();
        try {
            socket.connect(new InetSocketAddress(dtoNew.getDomain(), dtoNew.getPort()), dtoNew.getTimeout());
            isConnected = socket.isConnected();
        } catch (IOException e) {
            LOGGER.info("域名:{}:{} 连接异常:{}", dtoNew.getDomain(), dtoNew.getPort(), e.getMessage());
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                LOGGER.info("socket关闭失败异常信息:{}", e.getMessage());
            }
        }
        return isConnected;
    }

    /**
     * 根据字符串创建域名对象
     *
     * @param dto
     * @return
     */
    private static ExeDomainDTO createExeDomainDTObyString(ExeDomainReqDTO dto) {
        ExeDomainDTO domainDTO = new ExeDomainDTO();
        Pattern pattern = Pattern.compile(REGEX_RULE);
        Matcher matcher = pattern.matcher(dto.getDomain());
        if (matcher.find()) {
            domainDTO.setTimeout(dto.getTimeout() == null ? DEFAULT_TIMEOUT : dto.getTimeout());
            // group有两种格式:域名和端口:域名,需要判断一下
            String group = matcher.group();
            String[] splitStr = group.split(REGEX_SPLIT);
            if (splitStr.length == 1) {
                domainDTO.setDomain(splitStr[0]);
                domainDTO.setPort(DEFAULT_PORT);
            } else {
                domainDTO.setDomain(splitStr[0]);
                domainDTO.setPort(Integer.valueOf(splitStr[1]));
            }
            return domainDTO;
        }
        return null;
    }


}

到这里就结束了,记录这篇文章,便于以后参考。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值