springBoot多线程+异步处理

<一>:构建线程池

/**
 * 线程池
 * <p>
 * (1)判断核心线程数是否已满,核心线程数大小和corePoolSize参数有关,未满则创建线程执行任务
 * (2)若核心线程池已满,判断队列是否满,队列是否满和workQueue参数有关,若未满则加入队列中
 * (3)若队列已满,判断线程池是否已满,线程池是否已满和maximumPoolSize参数有关,若未满创建线程执行任务
 * (4)若线程池已满,则采用拒绝策略处理无法执执行的任务,拒绝策略和handler参数有关
 *
 */
@Configuration
@EnableAsync
public class AsyncExecutorConfig {
    
    

    @Bean(name = "commonAsyncPool")
    // 优先考虑,优先考虑被注解的对象注入
    public Executor commonAsyncPool() {
    
    
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 线程池创建时候初始化的线程数
        executor.setCorePoolSize(30);
        // 线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(150);
        // 用来缓冲执行任务的队列
        executor.setQueueCapacity(50);
        // 允许线程的空闲时间60秒:当超过了核心线程之外的线程,在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("serverCommonAsyncPool-");
        // 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,
        // 该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }


}

<二>:分离出来需要异步处理的方法

@Slf4j
@Service
@EnableAsync
public class SubscriptionServiceExecutor {
    
    
    @Autowired
    SwsJcCustTmRelativeMapper swsJcCustTmRelativeMapper;

    @Async("commonAsyncPool")
    public void insertMessage(List<MessageChildDto> childNode, MessageGroupDto group, Integer messageId, UserInfoDto custInfo, Integer rommId,
                              String rommName, SwsJcSubscriptionMsg subscriptionMsg) {
    
    
        Map keyMap = new HashMap();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (MessageChildDto child : childNode) {
    
    
            try {
    
    
                if (!keyMap.containsKey(child.getChildId())) {
    
    
                    keyMap.put(child.getChildId(), child.getName());
                    SwsJcSubscriptionReceive subscriptionReceive = new SwsJcSubscriptionReceive();
                    subscriptionReceive.setReceiveGroup(group.getName());
                    subscriptionReceive.setMessageId(messageId);
                    if (custInfo.getSourceWay() == null || (!"Android".equals(custInfo.getSourceWay()) && !"iOS".equals(custInfo.getSourceWay()))) {
    
    
                        subscriptionReceive.setReceiveUser(child.getChildId());
                    } else {
    
    
                        subscriptionReceive.setReceiveUser(child.getKey());
                    }
                    subscriptionReceive.setType(0);
                    subscriptionReceive.setDelStatus(1);//未删除
                    subscriptionReceive.setReceiveUserName(child.getName());
                    subscriptionReceive.setAliasId(child.getKey());
                    AppRoleEnum appRoleEnum = AppRoleEnum.getEnumByType(group.getName());
                    if (appRoleEnum != null) {
    
    
                        RoleEnum roleEnum = RoleEnum.getRoleEnumByType(appRoleEnum.getApp());
                        if (roleEnum != null) {
    
    
                            subscriptionReceive.setReceiveRole(roleEnum.getTypeName());
                        }
                    }
                    if (rommId != 0) {
    
    
                        subscriptionReceive.setRoomId(rommId);
                    }
                    subscriptionReceive.setRoomName(rommName);
                    swsJcSubscriptionReceiveMapper.insertSelective(subscriptionReceive);

                    if (custInfo.getSourceWay() == null || (!"Android".equals(custInfo.getSourceWay()) && !"iOS".equals(custInfo.getSourceWay()))) {
    
    
                        //发送消息
                        SwsYwSubscriptionInfo subscribeInfo = new SwsYwSubscriptionInfo();
                        subscribeInfo.setTmplId("KfgRqIRTrZeS5D4ABm8_68Y4bUrJsXVMsZdbnm04-3s");
                        subscribeInfo.setOpenId(subscriptionReceive.getReceiveUser());
                        SwsYwSubscriptionInfo scriptionInfo = swsYwSubscriptionInfoMapper.selectByPrimaryKey(subscribeInfo);
                        if (scriptionInfo != null) {
    
    
                            try {
    
    
                                Map<String, String> data = new HashMap<>();
                                data.put("time3", sf.format(subscriptionMsg.getSendDate()));
                                data.put("thing8", subscriptionMsg.getTheme());
                                data.put("name9", subscriptionMsg.getSendUserName());
                                Map res_map = sendSubscribeMessage(subscriptionReceive.getReceiveUser(), subscribeInfo.getTmplId(), "pages/messageAll/index", data);
                                if (!"ok".equals(res_map.get("errmsg"))) {
    
    
                                }
                            } catch (Exception e) {
    
    
                            }
                            swsYwSubscriptionInfoMapper.deleteByPrimaryKey(subscribeInfo);
                        }
                    }
                }
            } catch (Exception e) {
    
    
                log.error("消息发送失败:{}" + child.toString() + "/" + messageId);
            }
        }
    }

<三>调用该异步方法
注意:分离出来的异步方法与调用者不要在同一个类种,如果需要放入同一个类中,需要先获取该类的代理类,通过代理类取调用分类出来的方法

 //发送人员数量过大时,异步处理
 //异步处理时候,执行步骤一,然后执行步骤三,直接返回给前端 结果1, (步骤二与步骤三异步执行,其中步骤二是多线程处理,结果返回给前端时,步骤二不一定执行完毕了)
  String userRole = userInfoDto.getRoleCode();//步骤一
     
  subscriptionServiceExecutor.insertMessage(childNode, group, messageId, custInfo, rommId, rommName, subscriptionMsg);//步骤三
       
  String roleSelect = userInfoDto.getRoleSelect();//步骤三
  return 1;

题外:
一:对于tomcat这种web服务器而言,每一次请求。都会创建一条线程,对于全局变量,需要考虑线程安全问题,
二:对于需要异步处理的业务,子线程与父线程也需要考虑线程安全问题。(父线程的成员变量相对于子线程就是全局变量)
三:对于异步的代码,单次请求需要1分钟完成,在1分钟之内,再次请求多次,采用的是多线程处理(自行配置线程池),此时父线程的变量,对于子线程而言,存在线程安全问题。

猜你喜欢

转载自blog.csdn.net/qq_40579139/article/details/108649768