巨简单!Java多线程实战教学,均分处理数据!(支持Hibernate)

一、前言

今天遇到个bug,之前做的多线程接口一直报空,看了下代码发现配置的线程数超过了线程池最大线程数限制了,解决之后正好借这个机会来回顾记录下多线程操作。

注意:多线程接口因为是在旧系统中改造,既有hibernate框架已经做好封装,为了支持多线程选择用多线程发起请求调用单独业务接口处理。同理对于数据状态修改放到业务接口处理

二、代码

业务处理接口不再贴出,避免出现幂等以及脏数据。关键代码如下,实体类已改成测试用户类,自己调整即可。

调用接口

   @Autowired
    private SysUserService sysUserService;
    @Autowired
    private RkBatchPoolTest rkBatchPoolTest;

    @RequestMapping(value = "/projectRKBatch", method = RequestMethod.POST)
    public @ResponseBody SysResult projectRKBatch(@RequestParam("size") String size,@RequestParam(value = "type",required = false) String type) {
        log.info("————————————————————开始批量入库——————————————————————");
        if (StringUtils.isBlank(size)) {
            size = "1000";
        }
        if (StringUtils.isBlank(type)) {
            type = "NEW";
        }
        //查询出对应数据
        List<SysUser> userList = this.sysUserService.getUserListBySize(Integer.valueOf(size));
        log.info("批量入库条数" + userList.size());
        try {
            if ("NEW".equals(type)) {
                String rKBatchThreadUrl ="http//:localhost:8099/projectRK";//this.getRKBatchThreadUrl();
                return rkBatchPoolTest.rkBatchInit(userList,rKBatchThreadUrl);
            } else {
                //旧逻辑不在记录
                return SysResult.success();
            }
        } catch (Exception e) {
            log.error("批量入库异常:{},{}",e.getMessage(),e.getCause());
            return SysResult.fail(e.getMessage(),e.getCause());
        }
    }

RkBatchPoolTest 



import com.supermap.base.core.JsonMessage;
import com.supermap.dbserver.model.LSBCB1303;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author zeh.su
 * @Date 2024-07-29 14:20
 * @Description
 **/
@Component
public class RkBatchPoolTest {

    @Resource
    private RestTemplateConfig restTemplateConfig;

    private static final Logger logger = LoggerFactory.getLogger(RkBatchPoolTest.class);

    @Value("${thread.maxThread}")
    private int maxThread; // 单任务中最大线程数

    //均分 List
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {
        List<List<T>> result = new ArrayList<List<T>>();
        int remaider = source.size() % n;  //(先计算出余数)
        int number = source.size() / n;  //然后是商
        int offset = 0;//偏移量
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remaider > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remaider--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }

    public JsonMessage rkBatchInit(List<LSBCB1303> bwids, String rKBatchThreadUrl) throws ExecutionException, InterruptedException {
        Integer coreSize = maxThread;
        logger.info("批量入库线程数:{}",coreSize);
        logger.info("批量入库最大线程数:{}","48");
        JsonMessage msg = new JsonMessage();
        try {
            List<List<LSBCB1303>> lists = averageAssign(bwids, coreSize);
            ExecutorService pool = new ThreadPoolExecutor(coreSize, 48, 6, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
            List<RkCallable> callableList = new ArrayList<>();
            for (Integer i = 0; i < coreSize; i++) {
                RkCallable rkCallable = new RkCallable(lists.get(i), restTemplateConfig, rKBatchThreadUrl);
                callableList.add(rkCallable);
            }
            List<Future<JsonMessage>> futures = pool.invokeAll(callableList);
            for (Future<JsonMessage> future : futures) {
                logger.info("批量入库结果:",future.get().toString());
            }
        } catch (Exception e) {
            logger.error("批量入库线程初始化异常:" + e.getMessage());
            logger.error("批量入库线程初始化异常:" + e.getCause());
            msg.setState(false);
            msg.setMsg("批量入库线程初始化异常"+e.getMessage());
        }
        msg.setState(true);
        msg.setMsg("批量入库完毕");
        return msg;
    }
}


RkCallable

package com.hua.utils;

import com.hua.config.RestTemplateConfig;
import com.hua.entity.SysUser;
import com.hua.vo.SysResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;

class RkCallable implements Callable<SysResult> {
    private static final Logger logger = LoggerFactory.getLogger(RkCallable.class);
    //无法注解注入
    RestTemplateConfig restTemplateConfig;

    private List<SysUser> n;

    String rKBatchThreadUrl;

    public RkCallable(List<SysUser> n, RestTemplateConfig config, String url) {
        this.n = n;
        this.restTemplateConfig = config;
        this.rKBatchThreadUrl = url;
    }

    @Override
    public SysResult call() throws Exception {
        try {
           return rkBatch(n, rKBatchThreadUrl);
        } catch (Exception e) {
            logger.error(e.getMessage());
            System.out.println(Thread.currentThread().getName() + e.getMessage());
            return SysResult.fail(e.getMessage(),e.getCause());
        }
    }

    public SysResult rkBatch(List<SysUser> dataList, String rKBatchThreadUrl) throws Exception {
        logger.info(Thread.currentThread().getName() + "开始执行批量入库任务 数量:" + dataList.size());
        RestTemplate restTemplate = restTemplateConfig.restTemplate();
        SysResult rkRes;
        for (SysUser data : dataList) {
            try {
                ResponseEntity<SysResult> resultResponseEntit = restTemplate.postForEntity(rKBatchThreadUrl, data, SysResult.class);
                rkRes = resultResponseEntit.getBody();
                if (200 == rkRes.getStatus()) {
                    System.out.println(data.getId() + ":入库成功");
                } else {
                    System.out.println(data.getId() + ":入库失败");
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
                System.out.println(Thread.currentThread().getName() + e.getMessage());
                continue;
            }
            // 备用提升性能
            Thread.sleep(500);
        }
        logger.info(Thread.currentThread().getName() + "批量入库任务结束" + new Date().toString());
        System.out.println(Thread.currentThread().getName() + "批量入库任务结束" + new Date().toString());
        return SysResult.success();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值