所谓线程隔离就是在和多个外系统交互的时候将线程分成多个
优点:
(1)某些下游服务处理请求时间过长,创建三个静态线程池,针对不同的下游服务的请求只调用各自的线程池中的线程进行处理。不会因其他下游服务消费请求耗时长导致不能正常清分数据给其他服务。实现资源隔离。
(2)实现对下游请求的限流作用,例如前端请求qps为1000次/秒。使用静态线程池,初始核心线程数为50,又因为与下游服务的请求是实时接口,故该50个请求是同步阻塞的。即:请求下游服务的qps为50次/秒。
1.业务和线程方法如下:
package com.picccdyf.sff.inter.domain.distribute.service;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.picccdyf.sff.inter.domain.distribute.entity.InterDistributeDO;
import com.picccdyf.sff.inter.domain.distribute.entity.InterExchangeThreadPoolParameterDO;
import com.picccdyf.sff.inter.domain.distribute.entity.InterInvoiceThreadPoolParameterDO;
import com.picccdyf.sff.inter.domain.distribute.entity.InterSffThreadPoolParameterDO;
import com.picccdyf.sff.inter.infrastructure.common.Constants;
import cwzx.cdyf.common.common.InitService;
import cwzx.cdyf.common.common.SpringContextUtil;
import cwzx.cdyf.common.exception.PiccCommonException;
import cwzx.cdyf.common.log.LogHelper;
import org.apache.cxf.common.i18n.Exception;
import org.apache.tomcat.jni.Thread;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* description: InterDistributeSwitchManager 根据systemcode选择使用对应的线程池调用清分方法
*
* @author zhilong.xu
* @since 2020-10-23 13:53:41
*/
@Service
@InitService
@Lazy
public class InterDistributeSwitchSystemManager {
/**
* 初始化线程池
*/
private static ThreadFactory namedThreadFactorySff = new ThreadFactoryBuilder().setNameFormat("INTERDISTRIBUTESff" + "-POOL-%d").build();
private static final ThreadPoolExecutor THREADPOOLSff;
private static ThreadFactory namedThreadFactoryExchange = new ThreadFactoryBuilder().setNameFormat("INTERDISTRIBUTEExchange" + "-POOL-%d").build();
private static final ThreadPoolExecutor THREADPOOLExchange;
private static ThreadFactory namedThreadFactoryInvoice = new ThreadFactoryBuilder().setNameFormat("INTERDISTRIBUTEInvoice" + "-POOL-%d").build();
private static final ThreadPoolExecutor THREADPOOLInvoice;
static {
//获取缴费线程池配置参数
InterExchangeThreadPoolParameterDO beanExchange = SpringContextUtil.getBean(InterExchangeThreadPoolParameterDO.class);
//获取发票线程池配置参数
InterInvoiceThreadPoolParameterDO beanInvoice = SpringContextUtil.getBean(InterInvoiceThreadPoolParameterDO.class);
//获取新收付费线程池配置参数
InterSffThreadPoolParameterDO beanSff = SpringContextUtil.getBean(InterSffThreadPoolParameterDO.class);
//初始化新收付费线程池
THREADPOOLSff = new ThreadPoolExecutor(beanSff.getCorepoolsize(), beanSff.getMaximumpoolsize(), beanSff.getKeepalivetime(), TimeUnit.SECONDS, new LinkedBlockingDeque<>(beanSff.getCapacity()), namedThreadFactorySff, new ThreadPoolExecutor.AbortPolicy());
//初始化缴费线程池
THREADPOOLExchange = new ThreadPoolExecutor(beanExchange.getCorepoolsize(), beanExchange.getMaximumpoolsize(), beanExchange.getKeepalivetime(), TimeUnit.SECONDS, new LinkedBlockingDeque<>(beanExchange.getCapacity()), namedThreadFactoryExchange, new ThreadPoolExecutor.AbortPolicy());
//初始化发票线程池
THREADPOOLInvoice = new ThreadPoolExecutor(beanInvoice.getCorepoolsize(), beanInvoice.getMaximumpoolsize(), beanInvoice.getKeepalivetime(), TimeUnit.SECONDS, new LinkedBlockingDeque<>(beanInvoice.getCapacity()), namedThreadFactoryInvoice, new ThreadPoolExecutor.AbortPolicy());
}
/***
* description: 依据systemcode选择调用对应的线程池进行清分
* @param startTime 开始清分时间
* @param distributeDO 清分数据
* @param systemCodes 系统代码集合
* @param uuid 主键
* @author zhilong.xu
* @since 2020/9/8 19:47
*/
public void distributeSystemCods(Date startTime, InterDistributeDO distributeDO, List<String> systemCodes, String uuid) {
try {
//开启线程,依据systemCodes清分至各个微服务
for (String systemCode : systemCodes) {
switch (systemCode) {
//清分发票
case Constants.SYSTEM_CODE.INVOICE:
THREADPOOLInvoice.execute(new InterDistributeThreadTaskManager(startTime, distributeDO, uuid, systemCode));
break;
//清分新收付费
case Constants.SYSTEM_CODE.SFF:
THREADPOOLSff.execute(new InterDistributeThreadTaskManager(startTime, distributeDO, uuid, systemCode));
break;
//清分缴费
case Constants.SYSTEM_CODE.EXCHANGE:
THREADPOOLExchange.execute(new InterDistributeThreadTaskManager(startTime, distributeDO, uuid, systemCode));
break;
default:
throw new PiccCommonException("systemcode不存在");
}
}
} catch (Exception e) {
StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
LogHelper.error(stackTraceElement, e, e.getMessage());
}
}
}
2.在上面给线程池设置大小的时候,设计成可配置的,可以方便根据不同环境进行设置不同的参数,而且就算没有配置也会有默认的配置;具体如下
package com.picccdyf.sff.inter.domain.distribute.entity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* description: InterExchangeThreadPoolParameterDO 新收付费静态线程池相关参数配置
*
* @author zhilong.xu
* @since 2020-10-25 14:05:04
*/
@Component
public class InterSffThreadPoolParameterDO {
@Value("#{T(java.lang.Integer).parseInt('${sffthreadpool.corepoolsize:500}')}")
private Integer corepoolsize;
@Value("#{T(java.lang.Integer).parseInt('${sffthreadpool.maximumpoolsize:500}')}")
private Integer maximumpoolsize;
@Value("#{T(java.lang.Integer).parseInt('${sffthreadpool.keepalivetime:60}')}")
private Long keepalivetime;
@Value("#{T(java.lang.Long).parseLong('${sffthreadpool.capacity:10000}')}")
private Integer capacity;
public Integer getCorepoolsize() {
return corepoolsize;
}
public Integer getMaximumpoolsize() {
return maximumpoolsize;
}
public Long getKeepalivetime() {
return keepalivetime;
}
public Integer getCapacity() {
return capacity;
}
@Override
public String toString() {
return "InterSffThreadPoolParameterDO{" +
"corepoolsize=" + corepoolsize +
", maximumpoolsize=" + maximumpoolsize +
", keepalivetime=" + keepalivetime +
", capacity=" + capacity +
'}';
}
}
3.主流程采用懒加载的方式进行,就是为了解决读取不到线程相关的配置
/**
* 清分数据 因该类为懒加载,故不使用Autowired注入方式
*/
private InterDistributeSwitchSystemManager distributeSwitchSystemManager;
主流程调用:
//获取调用清分模块的当前系统时间
Date distributeStartTime = new Date();
//只有第一次才将interdistributeSwitchManager加载进spring容器
if (StringUtil.isNull(distributeSwitchSystemManager)) {
this.distributeSwitchSystemManager = SpringContextUtil.getBean(InterDistributeSwitchSystemManager.class);
}
// 调用清分模块
distributeSwitchSystemManager.distributeSystemCods(distributeStartTime, interDistributeDO, systemCodes, interLogDO.getUuid());