1. 司机队伍对象

public class DriverQueue {// 空闲司机队伍private static Map<Integer, Driver> freeDrivers = new ConcurrentHashMap<>();// 等待(派单中)司机队伍private static Map<Integer, Driver> waitDrivers = new ConcurrentHashMap<>();// 忙碌(已接单)司机队伍private static Map<Integer, Driver> busyDrivers = new ConcurrentHashMap<>();
}

2. 任务队列

/*** 任务队列* 如果在取任务时没有任务,则阻塞* @author LiLongjian**/
public class TaskQueue {private static TaskQueue instance;private static BlockingQueue<DispatchRecord> queue = null;private TaskQueue(){queue = new LinkedBlockingDeque<>();}public static TaskQueue getInstance(){if(instance == null){instance = new TaskQueue();}return instance;}public boolean contain(int customerId) {for (DispatchRecord record : queue) {if (record.getCustomerId() == customerId) {return true;}}return false;}/*** 获取队列大小* @return*/public int getSize(){return queue.size();}/*** 放入队列中* @param obj*/public void put(DispatchRecord obj){if(obj != null){try {queue.put(obj);} catch (InterruptedException e) {e.printStackTrace();}}}/*** 放入队列中* @param objs*/public void putAll(Collection<DispatchRecord> objs){if(objs != null){queue.addAll(objs);}}/*** 从队列中取出一个* @return*/public DispatchRecord take(){try {return queue.take();} catch (InterruptedException e) {e.printStackTrace();}return null;}}

3. 自动派单(任务分派)主线程:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.text.ParseException;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;/*** 从任务队列里取到任务,自动派单给业务员* @author LiLongjian**/
@Component
public class AutoDispatchTaskThread implements Runnable {private static final Logger logger = LoggerFactory.getLogger(AutoDispatchTaskThread.class);private boolean stop = false;@AutowiredExecutor executor;@Overridepublic void run() {System.out.println("==> 开始自动派单线程");try{while(!stop){// 1.获取下一个任务DispatchRecord record = TaskQueue.getInstance().take();if (record != null) {// 2.执行任务logger.info("==> 订单:" + record.getOrderInfo().getId() + "开始派单");long diffMinute = DateUtil.calcDiffMinute(record.getOrderInfo().getOrderTime());if (diffMinute > 8) {logger.error("==> 等待时间超过八分钟,自动取消订单");} else {dispatch(record);}}}}catch(Throwable t){logger.error(t.getMessage(),t);}}private void dispatch(DispatchRecord record) throws ParseException {DispatchTaskThread thread = new DispatchTaskThread(record);executor.execute(thread);}
}

4. 派单线程

import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import com.demo.dispatch.DrivingApplication;
import com.demo.dispatch.common.GlobalConstant;
import com.demo.dispatch.common.OrderStatus;
import com.demo.dispatch.model.OrderInfo;
import com.demo.dispatch.service.OrderInfoService;
import com.demo.dispatch.utils.BusinessUtil;
import com.demo.dispatch.utils.DateUtil;
import com.demo.dispatch.utils.MqttUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.text.ParseException;
import java.util.List;
import java.util.Map;
import java.util.Set;public class DispatchTaskThread implements Runnable {Logger logger = LoggerFactory.getLogger(DispatchTaskThread.class);// 任务记录对象private DispatchRecord record;// MQTT发送工具private MqttUtil mqttUtil;// 订单Service对象OrderInfoService orderInfoService;public DispatchTaskThread(DispatchRecord record) {this.record = record;this.mqttUtil = DrivingApplication.context.getBean(MqttUtil.class);this.orderInfoService = DrivingApplication.context.getBean(OrderInfoService.class);}@SneakyThrows@Overridepublic void run() {OrderInfo orderInfo = record.getOrderInfo();String logHead = Thread.currentThread().getId() + "-" + orderInfo.getId();int orderId = orderInfo.getId();// 判断是否继续派单boolean isContinueDispatch = isContinueDispatch(orderId, logHead);if (!isContinueDispatch) {return;}// 开始派单try {// 获取空闲司机列表Map<Integer, Driver> freeDrivers = DriverQueue.getFreeDrivers();Set<Integer> keySet = freeDrivers.keySet();logger.info(logHead + " ==> 当前空闲司机" + keySet);if (freeDrivers.size() == 0) {logger.error(logHead + " ==> 当前无司机在接单,重新派单");// 等待五秒钟重新派单Thread.sleep(5000);TaskQueue.getInstance().put(record);return;}// 就近匹配司机列表List<Driver> matchedDrivers = BusinessUtil.matchDrivers(freeDrivers, orderInfo.getStartLongitude(), orderInfo.getStartLatitude());// 执行派单逻辑for (Driver driver : matchedDrivers) {int driverId = driver.getId();// 判断司机是否已接单或已下线Driver freeDriver = DriverQueue.getFreeDriver(driverId);if (freeDriver == null) {logger.error(logHead + " ==> 司机(编号" + driverId + ")已接单或下线,派单给下一个");break;}// 1.将司机从空闲队列移动到等待队列DriverQueue.moveFromFreeToWait(driverId);// 2.发送MQTT消息到客户端String topic = GlobalConstant.DRIVER_TOPIC_FRONT + driverId;JSONObject payload = (JSONObject) JSONObject.toJSON(orderInfo);String s = mqttUtil.sendMsg(topic, payload);logger.info(logHead + " ==> 派单到【" + driver.getId() + ":" + driver.getName() + "】消息发送成功:" + s);// 3.等待五秒,第一次查询订单状态Thread.sleep(5000);// 判断司机是否空闲(下线判断)if (!isDriverWait(driverId)) {TaskQueue.getInstance().put(record);return;}OrderInfo orderInfoTemp = orderInfoService.getById(orderId);int orderStatus = orderInfoTemp.getOrderStatus();logger.info(logHead + " ==> 第一次查询订单状态:" + orderStatus + orderInfoTemp.getOrderStatusDesc());// 判断订单是否已接单或取消if (isRunningOrCancel(orderId, logHead, orderInfoTemp.getOrderStatus())) {// 判断订单是否已取消if (orderStatus == OrderStatus.CANCEL.getCode()) {DriverQueue.moveFromWaitToFree(driverId);}return;}// 4.等待五秒,第二次查询订单状态Thread.sleep(5000);// 判断司机是否等待中(下线判断)if (!isDriverWait(driverId)) {TaskQueue.getInstance().put(record);return;}orderInfoTemp = orderInfoService.getById(orderId);orderStatus = orderInfoTemp.getOrderStatus();// 判断订单是否已接单或取消if (isRunningOrCancel(orderId, logHead, orderInfoTemp.getOrderStatus())) {// 判断订单是否已取消if (orderStatus == OrderStatus.CANCEL.getCode()) {DriverQueue.moveFromWaitToFree(driverId);}return;}// 5.等待五秒,第三次查询订单状态Thread.sleep(5000);// 判断司机是否等待中(下线判断)if (!isDriverWait(driverId)) {TaskQueue.getInstance().put(record);return;}orderInfoTemp = orderInfoService.getById(orderId);orderStatus = orderInfoTemp.getOrderStatus();// 判断订单是否已接单或取消if (isRunningOrCancel(orderId, logHead, orderInfoTemp.getOrderStatus())) {// 判断订单是否已取消if (orderStatus == OrderStatus.CANCEL.getCode()) {DriverQueue.moveFromWaitToFree(driverId);}return;}// 6.等待十五秒后无人接单,将司机放到空闲队列if (isDriverWait(driverId)) {DriverQueue.moveFromWaitToFree(driverId);}}// 所有司机都没有接单,将任务重新放到队列中TaskQueue.getInstance().put(record);} catch (Exception e) {e.printStackTrace();logger.error(logHead + " ==> 出错了,将任务重新放到队列中");TaskQueue.getInstance().put(record);}}private boolean isContinueDispatch(int orderId, String logHead) throws ParseException {OrderInfo orderInfo = orderInfoService.getById(orderId);// 判断订单状态if (isRunningOrCancel(orderId, logHead, orderInfo.getOrderStatus())) {return false;}// 下单超过八分钟自动取消long diffMinute = DateUtil.calcDiffMinute(orderInfo.getOrderTime());if (diffMinute > 8) {logger.error(logHead + " ==> 等待时间超过八分钟,自动取消订单");return false;}return true;}private boolean isRunningOrCancel(int orderId, String logHead, int orderStatus) {if (orderStatus == OrderStatus.RECEIVED.getCode()) {// 司机已接单,结束派单logger.info(logHead + " ==> 订单【" + orderId + "】已被接单,停止派单");return true;} else if (orderStatus == OrderStatus.RUNNING.getCode()) {// 司机正在代驾,结束派单logger.info(logHead + " ==> 订单【" + orderId + "】正在代驾,停止派单");return true;} else if (orderStatus == OrderStatus.CANCEL.getCode()) {// 订单已取消logger.info(logHead + " ==> 订单【" + orderId + "】已取消,停止派单");return true;}return false;}private boolean isDriverFree(int driverId) {return DriverQueue.getFreeDriver(driverId) != null;}private boolean isDriverWait(int driverId) {return DriverQueue.getWaitDriver(driverId) != null;}private boolean isDriverBusy(int driverId) {return DriverQueue.getBusyDriver(driverId) != null;}}

过程说明:

1. 由一个派单主线程去监听下单,一旦有新的订单就会从线程池中创建一个新的线程去执行具体的派单逻辑。

2. 接单者队伍直接存储于三个ConcurrentHashMap(分别表示空闲、忙碌、等待)中。在派单逻辑中,会从空闲队伍中获取到派单对象A,并将A移动到等待队伍中,随后线程等待15秒,若A接单则将其移动到忙碌队伍,若A15秒未接单,则将其放回空闲队列,继续获取下一个空闲对象进行派单,如此往复。

基于多线程的自动派单系统设计相关推荐

  1. 【设计方案分享】基于单片机温度监测监控报警系统设计-基于单片机钞票自动智能识别系统设计-基于单片机乒乓球游戏机控制系统设计-基于单片机温度监测监控报警系统设计-基于单片机矩阵键盘的电子密码锁设计

    820基于单片机温度监测监控报警系统设计-设计资料 温度监测器功能描述: 1.主控芯片用的是51单片机(STC89C51). 2.使用温度传感器DS18b20采集温度. 3.用1602液晶显示显示温度 ...

  2. 基于单片机乒乓球游戏机控制系统设计-基于单片机矩阵键盘的电子密码锁设计-基于单片机温度监测监控报警系统设计-基于单片机钞票自动智能识别系统设计-设计资料【转发分享】

    819基于单片机乒乓球游戏机控制系统设计-设计资料下载 乒乓球游戏机设计任务为: (1)使用乒乓游戏机的甲乙双方各在不同的位置发球或击球. (2)乒乓球的位置和移动方向由灯亮及依次点燃的方向决定,球移 ...

  3. java 实现自动派单(自动分配任务)

    需求: 最近要实现一个自动派单功能,就是如果有任务来了,那么任务平均分配给现有的员工,如果之前取了任务的员工下次来任务时就分配给下一个,如果有新员工则将员工添加到队列的最后,如果有员工离职就将员工信息 ...

  4. 【电路方案】基于单片机智能市电温度控制系统设计-基于单片机RGB颜色智能识别系统设计-基于单片机四路红外遥控开关电路设计-基于单片机自行车自动防盗报警系统设计-基于单片机智能无线病床呼叫系统设计

    822基于单片机智能无线病床呼叫系统设计-设计资料下载 硬件构成:单片机+最小系统+LCD1602液晶显示模块+无线收发模块+蜂鸣器模块+LED指示灯模块+按键模块 本设计基于STC89C51/52( ...

  5. 基于单片机的自动追日系统设计_基于单片机的自动浇花系统的设计

    龙源期刊网 http://www.qikan.com.cn 基于单片机的自动浇花系统的设计 作者:吴蓓 张阳 来源:<现代信息科技> 2018 年第 03 期 摘 要:为了解决人们生活中由 ...

  6. 基于多线程的Linux聊天室系统设计(C语言实现)

    LTS聊天室文件夹:包含客户端服务器源代码以及完成好的大作业 下载资源 服务器端代码 客户端代码 系统简介 用C语言编程实现linux简单的聊天室功能. 用户程序命名为client.c;服务器程序命名 ...

  7. 基于单片机的自动追日系统设计_一种太阳能光伏支架自动追日系统的制作方法...

    本实用新型涉及一种实现太阳能电池板双轴自动跟踪的控制系统,用于太阳能电池板自动追踪太阳的方位. 背景技术: 中国已成为世界公认的太阳能利用产业和市场大国.随着太阳能光伏发电在新能源市场中所占的比例逐年 ...

  8. 【客户下单】后台系统自动分单成功生成工单发送短信

    [客户下单]后台系统自动分单成功生成工单发送短信 自动分单成功,后台生成工单发送短信,否则进入人工分单流程. 生成工单,发送短信的方法抽取: //抽取的方法:生成工单 发送短信 private voi ...

  9. 【客户下单】后台系统匹配分区关键字实现自动分单

    [客户下单]后台系统基于分区关键字匹配实现自动分单 通过前端传递过来的"省市区",找到区域,在通过区域找到分区,将客户发货地址与分区的关键字进行匹配,如果包含分区的关键字或辅助关键 ...

最新文章

  1. 从数理统计简史中看正态分布的历史由来
  2. 跨域 (1) jsonp 跨域
  3. Halcon知识:如何用mfc显示halcon读入图象
  4. 斯坦福大学机器学习第八课“神经网络的表示(Neural Networks: Representation)”
  5. linux设置NO_PROXY绕过代理
  6. Python变量类型
  7. 高中计算机教师考试专业知识,高中教师资格证计算机专业考试内容
  8. lsb算法 matlab隐藏图片算法,数字图像加密算法之空域LSB
  9. 工信部ICP备案管理系统滑动验证码破解
  10. Python网络爬虫开发实战,ADSL 拨号代理
  11. 三行情书 计算机网络,“学霸式”三行情书走红!句子很短,爱你如诗
  12. 调焦、变焦的原理和清晰度的关系
  13. 今天小暑是什么时间_2020年小暑具体时间是几点几分?小暑是什么意思?
  14. oracle中排序--拼音、笔画、偏旁部首
  15. 985 211计算机考研科目,考研想上985/211,你各科分数至少要考这么多!
  16. 静态库与动态库之间的区别
  17. C语言 程序 素数圈圈
  18. 25款顶级的jQuery表格插件
  19. origin作图所用数据点太多,做图时需要跳过数个数据给一个标记的方法
  20. Spring Cloud入门 -- Consul服务注册与发现(Hoxton.SR5版)

热门文章

  1. web前端下载excel文件
  2. Dubbox常见错误
  3. STL的string功能以及模拟实现
  4. java okhttp3异常_okhttp3 出现 .IOException: unexpec
  5. 金融科技大数据产品推荐:蓝金灵—基于大数据的电商企业供应链金融服务平台
  6. Koa2入门笔记 (上)
  7. 【车载开发系列】UDS诊断---读取周期标识符($0x2A)
  8. 【例4-6】香甜的黄油
  9. React82_useCallback()
  10. 【Reinforcement Learning】AlphaGo 如何使用的强化学习?