一、业务场景
1.需求
并发多个不同的业务,将所有业务的执行结果汇总返回,每个业务的需求时间不定,汇总返回耗时不能超过5秒(超时未返回结果的业务放弃)
2.分析
Thread 和 Runnable 不能返回结果,Callable 虽然可以返回子线程的结果,但是一旦调用get后就变成顺序执行而不是并发,Spring的MQ是异步并发的但是好像不能汇总结果,找了半天没找到现成的,所以就想着自己写一个吧。
二、实现方法
Thread 实现并发,synchronized 同步返回结果
1.统一业务返回格式
//返回数据的结构
@Data
class Res {
private String name; // 业务名称
private Integer code; // 状态码
private String errMsg; // 报错信息
private ArrayList<String> dataList; // 返回数据
}
2.创建数据缓冲区
// 数据缓冲区
class SynContainer {
// 业务执行结果汇总
ArrayList<Res> sList = new ArrayList<>();
// 业务执行完毕提交方法【同步锁】
public synchronized void submit(Res res) {
sList.add(res);
}
}
3.创建业务
// 业务线程1
class Service1 extends Thread{
SynContainer container;
public Service1(SynContainer container) {
this.container = container;
}
@Override
public void run() {
// 业务内容【自定义】 ------------------------------
// 模拟耗时200毫秒
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
// 模拟返回数据
ArrayList<String> s = new ArrayList<>();
s.add("数据1");
s.add("数据2");
s.add("数据3");
s.add("数据4");
Res r = new Res();
r.setName("业务1");
r.setCode(200);
r.setErrMsg("请求成功");
r.setDataList(s);
container.submit(r);
System.out.println("业务1执行完毕");
// ----------------------------------------------
}
}
// 业务线程2
class Service2 extends Thread{
SynContainer container;
public Service2(SynContainer container) {
this.container = container;
}
@Override
public void run() {
// 业务内容【自定义】 ------------------------------
// 模拟耗时200毫秒
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
// 模拟返回数据
ArrayList<String> s = new ArrayList<>();
s.add("数据1");
s.add("数据2");
s.add("数据3");
s.add("数据4");
Res r = new Res();
r.setName("业务2");
r.setCode(200);
r.setErrMsg("请求成功");
r.setDataList(s);
container.submit(r);
System.out.println("业务2执行完毕");
// ----------------------------------------------
}
}
4.创建计时器
// 计时器
class Timer {
private Date startTime;
private final long during;
public Timer(long during) {
this.during = during;
}
public void start() {
this.startTime = new Date();
}
public Boolean isTimeOver() {
Date now = new Date();
long t = now.getTime() - this.startTime.getTime();
return t>=during;
}
}
5.创建执行类
// 执行类
class Executor {
private final ArrayList<Thread> tList; // 业务队列
private final SynContainer container; // 数据缓冲区
private final long during; // 最大等待时间
public Executor(ArrayList<Thread> tList, SynContainer container, long during) {
this.tList = tList;
this.container = container;
this.during = during;
}
public ArrayList<Res> run() {
// 启动业务 -------------------------------------
for(Thread service: this.tList) service.start();
// ---------------------------------------------
// 初始化计时器 --------------------
Timer tm = new Timer(this.during);
tm.start();
// -------------------------------
// 线程状态监控【如果全部线程都执行完成 或者 未全部执行完成但总耗时超过了最大等待时间,就结束等待】-----
for(Thread service: this.tList) {
Thread.State state = service.getState();
while (state != Thread.State.TERMINATED && !tm.isTimeOver()) {
state = service.getState();
System.out.println("当前线程状态:" + state);
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
}
}
// ------------------------------------------------------------------------------------
// 汇总返回结果
return this.container.sList;
}
}
6.创建入口函数
public class MyThread {
public static void main(String[] args) {
// 初始化缓冲区
SynContainer container = new SynContainer();
// 创建业务队列
ArrayList<Thread> tList = new ArrayList<>();
tList.add(new Service1(container));
tList.add(new Service2(container));
// 最大等待时长
long during = 5000;
// 执行业务 汇总返回
ArrayList<Res> rList = new Executor(tList, container, during).run();
System.out.println(rList);
}
}
三、执行结果
ps:如有更好的实现方法希望大神指正(旺柴)