业务背景
1、服务端接收客户端路径规划命令,服务端执行路径规划,下发规划结果给客户端。
2、客户端能够发送取消路径规划命令,取消掉未执行的规划请求,如果已经执行则下发取消命令给目标客户端。
3、目前服务端路径规划服务只能单线程顺序执行,考虑使用阻塞队列实现此功能。
4、路径规划开始后,尝试取消算路。
模拟代码
import cn.hutool.core.thread.ThreadUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Objects;
import java.util.Scanner;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Date: 2021-06-29 20:11
*/
public class TestRRC {
//路径规划ID
final static AtomicInteger routeId = new AtomicInteger(0);
//取消标志
final static AtomicBoolean canceled = new AtomicBoolean(false);
//阻塞队列未设置容量大小
final static BlockingQueue<Rm> pending = new LinkedBlockingQueue();
final static ExecutorService service = Executors.newFixedThreadPool(1);
static {
//消费者线程 获取消息执行路径规划
service.execute(() -> {
while (true) {
Rm rm = null;
try {
rm = pending.take(); //获取队列数据,如果队列为空,线程进入等待
} catch (InterruptedException e) {
e.printStackTrace();
}
if (rm != null) {
route(rm.getMsg());
}
}
});
}
public static void main(String[] args) throws InterruptedException {
// List<String> queue = CollUtil.newArrayList("R1","C1","R2","R3","C3","R4","R5","R6","C6","C4");
//R代表算路请求,C代表取消算路,后边数字为算路消息ID
Scanner sc = new Scanner(System.in);
System.out.println("input msg");
while (true) {
String msg = sc.nextLine();
Rm rm = new Rm(msg);
if (msg.startsWith("R")) {
pending.put(rm); //算路请求放入待处理队列
} else {
if (!pending.remove(rm)) { //尝试删除算路消息
//未删除成功,执行删除算路方法,尝试在算路运行时取消算路
cancel(msg);
}
}
}
}
/**
* 算路开始后,尝试取消算路
*/
public static void cancel(String cmd) {
int id = Integer.valueOf(cmd.substring(1));
if (id == routeId.get()) {
canceled.set(true);
System.out.println("服务器端取消算路");
return;
}
System.out.println("下发算路取消命令 : " + cmd);
}
/**
* 模拟算路方法
*/
public static void route(String cmd) {
//算路开始设置当前算路ID
routeId.set(Integer.valueOf(cmd.substring(1)));
//算路开始前判断算路是否被取消
if (canceled.get()) {
canceled.set(false);
routeId.set(0);
return;
}
//模拟算路耗时
ThreadUtil.sleep(2000);
//算路结束后判断算路是否被取消
if (canceled.get()) {
canceled.set(false);
routeId.set(0);
return;
}
//算路未取消下发算路结果
System.out.println("下发算路结果 : " + cmd);
routeId.set(0);//重置算路ID
}
}
/**
* 封装消息
*/
@Data
@AllArgsConstructor
class Rm {
private Integer id;
private String msg;
public Rm(String msg) {
this.id = Integer.valueOf(msg.substring(1));
this.msg = msg;
}
//重写equals 根据id判断是否为同一对象
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Rm rm = (Rm) o;
return Objects.equals(id, rm.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}