1.概述
由于接到项目需求,需求细分用户群体,做针对性引导,实现用户策略
本教程,我将向你介绍利用Java,利用策略模式与ForkJoinPool实现用户策略。
在策略模式(Strategy Pattern)中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。
ForkJoinPool线程池最大的特点就是分叉(fork)合并(join),将一个大任务拆分成多个小任务,并行执行,再结合工作窃取模式(worksteal
)提高整体的执行效率,充分利用CPU资源。
2.步骤
下面是具体的步骤
步骤 | 描述 |
步骤1 | 创建策略类 |
步骤2 | 线程处理和策略处理 |
步骤3 | 线程调用 |
步骤4 | 演示 |
3.步骤详解
步骤1:创建策略类
使用interface
关键字,创建策略执行器
定义策略实现类 OnlineUpdateDateExecutor 和 SuccessRechargeCountExecutor
@Service("onlineUpdateDate")
public class OnlineUpdateDateExecutor implements IRuleExecutor<MemberDetailsDTO> {
@Override
public List<MemberDetailsDTO> execute(String value, List<MemberDetailsDTO> list) {
// 策略处理
} catch (Exception e) {
logger.error("OnlineUpdateDateExecutor handle {} Error", value, e);
}
return list;
}
}
@Service("successRechargeCount")
public class SuccessRechargeCountExecutor implements IRuleExecutor<MemberDetailsDTO> {
try {
// 策略处理具体内容
}
} catch (Exception e) {
logger.error("SuccessRechargeCountExecutor handle {} Error", value, e);
}
return list;
}
}
步骤2:MemberTask 继承RecursiveTask,对策略进行拆分。重点在于 comoute()方法中,这是一个递归方法,要是符合执行数量,直接执行。要是不符合,一分为二,mTask1创建一个新的子线程。mTask2执行 comoute()方法。直到全部符合执行数量。
通过SpringContextUtils.getBean(),获取到具体策略executor,executor 调用具体实现方法。
public class MemberTask extends RecursiveTask<List<MemberDetailsDTO>> {
private Logger logger = LoggerFactory.getLogger(MemberTask.class);
private static final long serialVersionUID = -3547606844432921913L;
/**
* 目标数据
*/
private List<MemberDetailsDTO> members;
/**
* 策略规则组
*/
private List<MemberPolicyRuleRelationDTO> frontVos;
/**
* 最大执行数量
*/
private int maxSize;
/**
* 起始节点
*/
private int start;
/**
* 终止节点
*/
private int end;
public MemberTask(List<MemberDetailsDTO> members, List<MemberPolicyRuleRelationDTO> frontVos,
int maxSize) {
this.members = members;
this.frontVos = frontVos;
this.maxSize = maxSize;
this.start = 0;
this.end = members.size();
}
@Override
protected List<MemberDetailsDTO> compute() {
if ((end - start) < maxSize) {
// 执行
return handle();
} else {
// 拆分
int mid = (start + end) / 2;
MemberTask mTask1 = new MemberTask(members.subList(start, mid), frontVos, maxSize);
mTask1.fork();
MemberTask mTask2 = new MemberTask(members.subList(mid, end), frontVos, maxSize);
List<MemberDetailsDTO> compute = mTask2.compute();
compute.addAll(mTask1.join());
return compute;
}
}
private List<MemberDetailsDTO> handle() {
// 执行规则过滤
List<MemberDetailsDTO> list = new ArrayList<>(this.members);
for (MemberPolicyRuleRelationDTO ruleRelationDTO : frontVos) {
IRuleExecutor<MemberDetailsDTO> executor = SpringContextUtils.getBean(ruleRelationDTO.getRuleBeanName(), IRuleExecutor.class);
if (StringUtils.isBlank(ruleRelationDTO.getValue())) {
continue;
}
list = executor.execute(ruleRelationDTO.getValue(), list);
logger.info("MemberDetailsDTOTask execute beanName:{}, memberSize:{}", ruleRelationDTO.getRuleBeanName(), CollectionUtils.isEmpty(list) ? 0 : list.size());
}
logger.info("MemberDetailsDTOTask execute end, memberSize:{}", CollectionUtils.isEmpty(list) ? 0 : list.size());
return list;
}
}
步骤3:线程调用
创建ForkJoinPool 线程池,提交任务,获取返回结果。关闭线程池。
public List<MemberDetailsDTO> check(Long policyId, List<MemberDetailsDTO> list) throws InterruptedException, ExecutionException {
logger.info("MemberRuleCheckImpl check start policyId:{},memberSize:{}", policyId, list.size());
// 查询指定策略
List<MemberPolicyRuleRelationDTO> relations = new ArrayList<>();
if (!StringUtils.isEmpty(policyId)){
relations = memberPolicyRuleRelationService.findRulesByPolicyId(policyId);
}
//如果策略集合为空 ,返回一个空集
if (CollectionUtils.isEmpty(relations)){
return new ArrayList<>();
}
ForkJoinPool forkJoinPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
ForkJoinTask<List<MemberDetailsDTO>> submit = forkJoinPool.submit(getPrivateTask(list, relations));
list = submit.get();
forkJoinPool.shutdown();
logger.info("MemberRuleCheckImpl check end policyId:{},memberSize:{}", policyId, list.size());
return list;
}
4.演示
运行一下,看看效果。
预设最大数量 maxSize 为4。members数量为5。
由于不符合最大数量。所以一分为二。mTask1数量为2,mTask2数量为3。
executor获取到OnlineUpdateDateExecutor
执行完,就得到需要的数据。
5.总结
通过以上的步骤,我们就成功的利用策略模式与ForkJoinPool实现用户策略。