堆垛机线程调度 输送线线程调度 监控线程调度

This commit is contained in:
liuhanqing
2025-09-25 14:15:35 +08:00
parent 9640507cfd
commit 0322611d7b
7 changed files with 140 additions and 238 deletions

View File

@@ -1,12 +1,21 @@
package com.ruoyi.schedule; package com.ruoyi.schedule;
import com.ruoyi.device.ddj.domain.MsgDdj; import com.ruoyi.device.ddj.domain.MsgDdj;
import com.ruoyi.device.ddj.service.IMsgDdjService;
import com.ruoyi.device.ssj.domain.DeviceSsj; import com.ruoyi.device.ssj.domain.DeviceSsj;
import com.ruoyi.device.ssj.service.IDeviceSsjService; import com.ruoyi.device.ssj.service.IDeviceSsjService;
import com.ruoyi.common.domain.PlcConnectInfo; import com.ruoyi.common.domain.PlcConnectInfo;
import com.ruoyi.schedule.plcRead.ddj.PlcDdjRead; import com.ruoyi.schedule.plcRead.ddj.PlcDdjRead;
import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead; import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead;
import com.ruoyi.common.domain.CustomThread; import com.ruoyi.common.domain.CustomThread;
import com.ruoyi.schedule.scheduleTask.ddj.Ddj1Thread;
import com.ruoyi.schedule.scheduleTask.monit.MonitoringThread;
import com.ruoyi.schedule.scheduleTask.ssj.floor1.Floor1BothWayInSsjThread;
import com.ruoyi.schedule.scheduleTask.ssj.floor1.Floor1BothWayOutSsjThread;
import com.ruoyi.schedule.scheduleTask.ssj.floor1.Floor1SingleSsjThread;
import com.ruoyi.schedule.scheduleTask.ssj.floor2.Floor2InSsjThread;
import com.ruoyi.schedule.scheduleTask.ssj.floor2.Floor2OutSsjThread;
import com.ruoyi.schedule.scheduleTask.ssj.floor2.LineSsjThread;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -20,10 +29,21 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j @Slf4j
public class ScheduleThread { public class ScheduleThread {
public CustomThread<PlcSsjRead> customSsjThread; public CustomThread<PlcSsjRead> plcSsjReadCustomThread;
public CustomThread<PlcDdjRead> customDdjThread; public CustomThread<PlcDdjRead> plcDdjReadCustomThread;
public CustomThread<Floor1BothWayInSsjThread> floor1BothWayInSsjCustomThread;
public CustomThread<Floor1BothWayOutSsjThread> floor1BothWayOutSsjCustomThread;
public CustomThread<Floor1SingleSsjThread> floor1SingleSsjCustomThread;
public CustomThread<Floor2InSsjThread> floor2InSsjCustomThread;
public CustomThread<Floor2OutSsjThread> floor2OutSsjCustomThread;
public CustomThread<LineSsjThread> lineSsjCustomThread;
public CustomThread<MonitoringThread> monitoringCustomThread;
public CustomThread<Ddj1Thread> ddj1CustomThread;
@Autowired @Autowired
private IDeviceSsjService deviceSsjService; private IDeviceSsjService deviceSsjService;
@Autowired
private IMsgDdjService msgDdjService;
private boolean isRun = false; private boolean isRun = false;
private boolean isRun2 = false; private boolean isRun2 = false;
@@ -45,47 +65,57 @@ public class ScheduleThread {
* 调度初始化 * 调度初始化
*/ */
private void scheduleInit() { private void scheduleInit() {
/* BsInSsjThread bsInSsjThread1 = new BsInSsjThread(); MonitoringThread monitoringThread = new MonitoringThread();
bsInSsjThread = new CustomThread<BsInSsjThread>(new Thread(bsInSsjThread1), bsInSsjThread1); monitoringCustomThread = new CustomThread<MonitoringThread>(new Thread(monitoringThread), monitoringThread);
JsInSsjThread jsInSsjThread1 = new JsInSsjThread();
jsInSsjThread = new CustomThread<JsInSsjThread>(new Thread(jsInSsjThread1), jsInSsjThread1);
BsOutSsjThread bsOutSsjThread1 = new BsOutSsjThread();
bsOutSsjThread = new CustomThread<BsOutSsjThread>(new Thread(bsOutSsjThread1), bsOutSsjThread1);
JsOutSsjThread jsOutSsjThread1 = new JsOutSsjThread();
jsOutSsjThread = new CustomThread<JsOutSsjThread>(new Thread(jsOutSsjThread1), jsOutSsjThread1);
BsPickSsjTread bsPickSsjTread1 = new BsPickSsjTread();
bsPickSsjThread = new CustomThread<BsPickSsjTread>(new Thread(bsPickSsjTread1), bsPickSsjTread1);
JsPickSsjTread jsPickSsjTread1 = new JsPickSsjTread();
jsPickSsjThread = new CustomThread<JsPickSsjTread>(new Thread(jsPickSsjTread1), jsPickSsjTread1);
SsjMonitorThread ssjMonitorThread1 = new SsjMonitorThread(); Floor1BothWayInSsjThread floor1BothWayInSsjThread = new Floor1BothWayInSsjThread();
ssjMonitorThread = new CustomThread<SsjMonitorThread>(new Thread(ssjMonitorThread1), ssjMonitorThread1);*/ floor1BothWayInSsjCustomThread = new CustomThread<Floor1BothWayInSsjThread>(new Thread(floor1BothWayInSsjThread), floor1BothWayInSsjThread);
Floor1BothWayOutSsjThread floor1BothWayOutSsjThread = new Floor1BothWayOutSsjThread();
floor1BothWayOutSsjCustomThread = new CustomThread<Floor1BothWayOutSsjThread>(new Thread(floor1BothWayOutSsjThread), floor1BothWayOutSsjThread);
Floor1SingleSsjThread floor1SingleSsjThread = new Floor1SingleSsjThread();
floor1SingleSsjCustomThread = new CustomThread<Floor1SingleSsjThread>(new Thread(floor1SingleSsjThread), floor1SingleSsjThread);
Floor2InSsjThread floor2InSsjThread = new Floor2InSsjThread();
floor2InSsjCustomThread = new CustomThread<Floor2InSsjThread>(new Thread(floor2InSsjThread), floor2InSsjThread);
LineSsjThread lineSsjThread = new LineSsjThread();
lineSsjCustomThread = new CustomThread<LineSsjThread>(new Thread(lineSsjThread), lineSsjThread);
Floor2OutSsjThread floor2OutSsjThread = new Floor2OutSsjThread();
floor2OutSsjCustomThread = new CustomThread<Floor2OutSsjThread>(new Thread(floor2OutSsjThread), floor2OutSsjThread);
Ddj1Thread ddj1Thread = new Ddj1Thread();
ddj1CustomThread = new CustomThread<Ddj1Thread>(new Thread(ddj1Thread), ddj1Thread);
} }
/** /**
* plc读取初始化 * plc读取初始化
*/ */
private void plcReadInit() { private void plcReadInit() {
String ip = "127.0.0.1"; ConcurrentHashMap<String, DeviceSsj> ssjList = new ConcurrentHashMap<>();
int port = 102;
PlcConnectInfo ssjPlcConnectInfo = new PlcConnectInfo(ip, port);
ConcurrentHashMap<String, DeviceSsj> list = new ConcurrentHashMap<>();
//获取要去取的输送机 //获取要去取的输送机
List<DeviceSsj> deviceSsjs = deviceSsjService.selectDeviceSsjList(new DeviceSsj()); List<DeviceSsj> deviceSsjs = deviceSsjService.selectDeviceSsjList(new DeviceSsj());
for (DeviceSsj deviceSsj : deviceSsjs) { for (DeviceSsj deviceSsj : deviceSsjs) {
list.put(deviceSsj.getDeviceCode(), deviceSsj); ssjList.put(deviceSsj.getDeviceCode(), deviceSsj);
} }
//plc输送机读取线程 //plc输送机读取线程
PlcSsjRead plcSsjRead = new PlcSsjRead(list, ssjPlcConnectInfo); PlcSsjRead plcSsjRead = new PlcSsjRead(ssjList, new PlcConnectInfo("127.0.0.1", 102));
Thread plcSsjReadThread = new Thread(plcSsjRead); Thread plcSsjReadThread = new Thread(plcSsjRead);
customSsjThread = new CustomThread<PlcSsjRead>(plcSsjReadThread, plcSsjRead); plcSsjReadCustomThread = new CustomThread<PlcSsjRead>(plcSsjReadThread, plcSsjRead);
//plc堆垛机读取现场 //plc堆垛机读取现场
ConcurrentHashMap<String, MsgDdj> list2 = new ConcurrentHashMap<>(); ConcurrentHashMap<String, MsgDdj> ddjList = new ConcurrentHashMap<>();
PlcDdjRead plcDdjRead = new PlcDdjRead(list2, ssjPlcConnectInfo); List<MsgDdj> msgDdjs = msgDdjService.selectMsgDdjList(new MsgDdj());
for (MsgDdj msgDdj : msgDdjs) {
ddjList.put("ddj"+msgDdj.getId(), msgDdj);
}
PlcDdjRead plcDdjRead = new PlcDdjRead(ddjList, new PlcConnectInfo("127.0.0.1", 102));
Thread plcDdjReadThread = new Thread(plcDdjRead); Thread plcDdjReadThread = new Thread(plcDdjRead);
customDdjThread = new CustomThread<PlcDdjRead>(plcDdjReadThread, plcDdjRead); plcDdjReadCustomThread = new CustomThread<PlcDdjRead>(plcDdjReadThread, plcDdjRead);
} }
@@ -93,8 +123,8 @@ public class ScheduleThread {
* 开始线程 * 开始线程
*/ */
public void startAllThread() { public void startAllThread() {
customSsjThread.getThread().start(); plcSsjReadCustomThread.getThread().start();
customDdjThread.getThread().start(); plcDdjReadCustomThread.getThread().start();
isRun = true; isRun = true;
} }
@@ -102,22 +132,14 @@ public class ScheduleThread {
* 开启线程2 * 开启线程2
*/ */
public void startAllThread2() { public void startAllThread2() {
/* //臂式入库线程调度 monitoringCustomThread.thread.start();
bsInSsjThread.getThread().start(); floor1BothWayInSsjCustomThread.thread.start();
//臂式出库线程调度 floor1BothWayOutSsjCustomThread.thread.start();
bsOutSsjThread.getThread().start(); floor1SingleSsjCustomThread.thread.start();
//臂式出库到位线程调度-wms电子屏交互 floor2InSsjCustomThread.thread.start();
bsPickSsjThread.getThread().start(); lineSsjCustomThread.thread.start();
//剪式入库线程调度 floor2OutSsjCustomThread.thread.start();
jsInSsjThread.getThread().start(); ddj1CustomThread.thread.start();
//剪式出库线程调度
//jsOutSsjThread.getThread().start();
//剪上出库到位线程调度-wms电子屏交互
//jsPickSsjThread.getThread().start();
//监控输送机
//ssjMonitorThread.getThread().start();*/
isRun2 = true; isRun2 = true;
} }
@@ -125,8 +147,8 @@ public class ScheduleThread {
* 停止线程 * 停止线程
*/ */
public void stopAllThread() { public void stopAllThread() {
customDdjThread.runnable.isRun = false; plcSsjReadCustomThread.runnable.isRun = false;
customSsjThread.runnable.isRun = false; plcDdjReadCustomThread.runnable.isRun = false;
plcReadInit(); plcReadInit();
isRun = false; isRun = false;
} }
@@ -135,12 +157,14 @@ public class ScheduleThread {
* 停止线程2 * 停止线程2
*/ */
public void stopAllThread2() { public void stopAllThread2() {
/*bsInSsjThread.runnable.isRun = false; monitoringCustomThread.runnable.isRun = false;
jsInSsjThread.runnable.isRun = false; floor1BothWayInSsjCustomThread.runnable.isRun = false;
bsOutSsjThread.runnable.isRun = false; floor1BothWayOutSsjCustomThread.runnable.isRun = false;
jsOutSsjThread.runnable.isRun = false; floor1SingleSsjCustomThread.runnable.isRun = false;
bsPickSsjThread.runnable.isRun = false; floor2InSsjCustomThread.runnable.isRun = false;
jsPickSsjThread.runnable.isRun = false;*/ lineSsjCustomThread.runnable.isRun = false;
floor2OutSsjCustomThread.runnable.isRun = false;
ddj1CustomThread.runnable.isRun = false;
scheduleInit(); scheduleInit();
isRun2 = false; isRun2 = false;
} }

View File

@@ -23,12 +23,12 @@ public class PlcDdjRead extends Thread {
public SiemensS7Net siemensS7Net = null; public SiemensS7Net siemensS7Net = null;
public static IReadWriteNet readWriteNet = null; public static IReadWriteNet readWriteNet = null;
private String ip; private final String ip;
private int port; private final int port;
private boolean success = false; private boolean success = false;
public PlcDdjRead(ConcurrentHashMap<String, MsgDdj> deviceDdjMap, PlcConnectInfo plcConnectInfo) { public PlcDdjRead(ConcurrentHashMap<String, MsgDdj> deviceDdjMap, PlcConnectInfo plcConnectInfo) {
this.deviceDdjMap = deviceDdjMap; PlcDdjRead.deviceDdjMap = deviceDdjMap;
this.ip = plcConnectInfo.getIp(); this.ip = plcConnectInfo.getIp();
this.port = plcConnectInfo.getPort(); this.port = plcConnectInfo.getPort();
} }
@@ -57,11 +57,10 @@ public class PlcDdjRead extends Thread {
reConnect(); reConnect();
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
// <20><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6>쳣<EFBFBD><ECB3A3><EFBFBD>˳<EFBFBD>ѭ<EFBFBD><D1AD> Thread.currentThread().interrupt();
Thread.currentThread().interrupt(); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<D0B6>־
return; return;
} catch (Exception e) { } catch (Exception e) {
log.info("********IP:" + this.ip + " port:" + this.port + "<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣 " + e.getMessage()); log.info("********IP:" + this.ip + " port:" + this.port + "<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣 " + e.getMessage());
} }
} }
@@ -103,7 +102,7 @@ public class PlcDdjRead extends Thread {
readWriteNet = siemensS7Net; readWriteNet = siemensS7Net;
} }
} catch (Exception ex) { } catch (Exception ex) {
log.info("********IP:" + this.ip + " port:" + this.port + "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD> " + ex.getMessage()); log.info("********IP:" + this.ip + " port:" + this.port + "连接失败 " + ex.getMessage());
} }
} }
@@ -124,7 +123,7 @@ public class PlcDdjRead extends Thread {
void reConnect() { void reConnect() {
closeServer(); closeServer();
ConnectServer(); ConnectServer();
log.info("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SSJ-PLC"); log.info("重新连接 SSJ-PLC");
} }
void closeServer() { void closeServer() {
@@ -134,13 +133,11 @@ public class PlcDdjRead extends Thread {
setIsConnect(false); setIsConnect(false);
} }
/// <20>Ѷ<EFBFBD><D1B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD> public static int WriteToDDJ(String address, byte[] data) {
public static int WritetoDDJ(String address, byte[] tsak) { int a = 0;
/*int a = 0;
if (readWriteNet != null) { if (readWriteNet != null) {
a = HslRead.WriteResultRender(readWriteNet.Write(address, tsak), address); a = HslRead.WriteResultRender(readWriteNet.Write(address, data), address);
} }
return a;*/ return a;
return 0;
} }
} }

View File

@@ -23,12 +23,12 @@ public class PlcSsjRead implements Runnable {
public SiemensS7Net siemensS7Net = null; public SiemensS7Net siemensS7Net = null;
public static IReadWriteNet readWriteNet = null; public static IReadWriteNet readWriteNet = null;
private String ip; private final String ip;
private int port; private final int port;
private boolean success = false; private boolean success = false;
public PlcSsjRead(ConcurrentHashMap<String, DeviceSsj> deviceSsjMap, PlcConnectInfo plcConnectInfo) { public PlcSsjRead(ConcurrentHashMap<String, DeviceSsj> deviceSsjMap, PlcConnectInfo plcConnectInfo) {
this.deviceSsjMap = deviceSsjMap; PlcSsjRead.deviceSsjMap = deviceSsjMap;
this.ip = plcConnectInfo.getIp(); this.ip = plcConnectInfo.getIp();
this.port = plcConnectInfo.getPort(); this.port = plcConnectInfo.getPort();
} }

View File

@@ -247,9 +247,9 @@ public class Ddj1Thread implements Runnable {
int jym = Tools.getJYM(taskNo, yph, ylh, ych, mbph, mblh, mbch, mlfs, xfwc); int jym = Tools.getJYM(taskNo, yph, ylh, ych, mbph, mblh, mbch, mlfs, xfwc);
byte[] sendData = Tools.sendDataToDevice(taskNo, null, yph, ylh, ych, mbph, mblh, mbch, mlfs, xfwc, jym); byte[] sendData = Tools.sendDataToDevice(taskNo, null, yph, ylh, ych, mbph, mblh, mbch, mlfs, xfwc, jym);
if (devId==1){ if (devId==1){
return PlcDdjRead.WritetoDDJ("DB61.0", sendData); return PlcDdjRead.WriteToDDJ("DB61.0", sendData);
}else { }else {
return PlcDdjRead.WritetoDDJ("DB61.0", sendData); return PlcDdjRead.WriteToDDJ("DB61.0", sendData);
} }
} }

View File

@@ -0,0 +1,48 @@
package com.ruoyi.schedule.scheduleTask.monit;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.device.ddj.service.IMsgDdjService;
import com.ruoyi.device.ssj.domain.DeviceSsj;
import com.ruoyi.device.ssj.service.IDeviceSsjService;
import com.ruoyi.schedule.plcRead.ddj.PlcDdjRead;
import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead;
import lombok.extern.slf4j.Slf4j;
/**
* 监控线程
*/
@Slf4j
public class MonitoringThread implements Runnable {
public boolean isRun = true;
private IDeviceSsjService deviceSsjService;
private IMsgDdjService msgDdjService;
public void init() {
deviceSsjService = SpringUtils.getBean(IDeviceSsjService.class);
msgDdjService = SpringUtils.getBean(IMsgDdjService.class);
}
@Override
public void run() {
init();
while (isRun){
for (String ssjCode : PlcSsjRead.deviceSsjMap.keySet()) {
DeviceSsj deviceSsj = PlcSsjRead.deviceSsjMap.get(ssjCode);
deviceSsjService.updateDeviceSsj(deviceSsj);
}
for (String ddjCode : PlcDdjRead.deviceDdjMap.keySet()) {
msgDdjService.updateMsgDdj(PlcDdjRead.deviceDdjMap.get(ddjCode));
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -1,83 +0,0 @@
package com.ruoyi.schedule.scheduleTask.ssj.common;
import com.ruoyi.api.service.IApiService;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.device.ssj.domain.DeviceSsj;
import com.ruoyi.queue.agv.service.IAgvQueueService;
import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 监控线程
*/
@Slf4j
public class MonitoringThread implements Runnable {
public HashMap<String, List<String>> ssjCodeList;
private IApiService apiService;
private IAgvQueueService agvQueueService;
public boolean isRun = true;
public void init() {
ssjCodeList = new HashMap<>();
ArrayList<String> ssjCodes = new ArrayList<>();
ssjCodes.add("L1002");
ssjCodes.add("L1004");
ssjCodeList.put("in", ssjCodes);
apiService = SpringUtils.getBean(IApiService.class);
agvQueueService = SpringUtils.getBean(IAgvQueueService.class);
log.info("初始化服务 {},{}", apiService, agvQueueService);
}
@Override
public void run() {
init();
while (isRun){
for (String type : ssjCodeList.keySet()) {
switch ( type){
case "in":
//生产线入库
for (String ssjCode : ssjCodeList.get(type)) {
try {
if (PlcSsjRead.deviceSsjMap.containsKey(ssjCode)) {
inDispatch(PlcSsjRead.deviceSsjMap.get(ssjCode));
} else {
log.error("设备不存在 ssjCode{}", ssjCode);
}
} catch (RuntimeException e) {
log.error(e.getMessage(),e);
}
}
break;
}
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void inDispatch(DeviceSsj inSsjDevice) {
//如果入库请求1 并且 托盘码不为空
if (inSsjDevice.getDw() == 1 && inSsjDevice.getTaskNo() > 0 && inSsjDevice.getRkqq() == 1) {
//查询货位 排列层
//查询入口 排列层
//生成堆垛机队列
}
}
}

View File

@@ -1,84 +0,0 @@
package com.ruoyi.schedule.scheduleTask.ssj.common;
import com.ruoyi.api.service.IApiService;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.device.ssj.domain.DeviceSsj;
import com.ruoyi.queue.agv.service.IAgvQueueService;
import com.ruoyi.schedule.plcRead.ssj.PlcSsjRead;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 巷道口线程 到位+任务号+入库作业+货位未分配 请求wms生成货位 到位+任务号+入库作业+货位已分配 生成堆垛机入库队列
*/
@Slf4j
public class RoadwaySsjThread implements Runnable{
public HashMap<String, List<String>> ssjCodeList;
private IApiService apiService;
private IAgvQueueService agvQueueService;
public boolean isRun = true;
public void init() {
ssjCodeList = new HashMap<>();
ArrayList<String> ssjCodes = new ArrayList<>();
ssjCodes.add("L1002");
ssjCodes.add("L1004");
ssjCodeList.put("in", ssjCodes);
apiService = SpringUtils.getBean(IApiService.class);
agvQueueService = SpringUtils.getBean(IAgvQueueService.class);
log.info("初始化服务 {},{}", apiService, agvQueueService);
}
@Override
public void run() {
init();
while (isRun){
for (String type : ssjCodeList.keySet()) {
switch ( type){
case "in":
//生产线入库
for (String ssjCode : ssjCodeList.get(type)) {
try {
if (PlcSsjRead.deviceSsjMap.containsKey(ssjCode)) {
inDispatch(PlcSsjRead.deviceSsjMap.get(ssjCode));
} else {
log.error("设备不存在 ssjCode{}", ssjCode);
}
} catch (RuntimeException e) {
log.error(e.getMessage(),e);
}
}
break;
}
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void inDispatch(DeviceSsj inSsjDevice) {
//如果入库请求1 并且 托盘码不为空
if (inSsjDevice.getDw() == 1 && inSsjDevice.getTaskNo() > 0 && inSsjDevice.getRkqq() == 1) {
//查询货位 排列层
//查询入口 排列层
//生成堆垛机队列
}
}
}