Java后端线程
在主程序HandleProc中设置4个线程:
//全局时间线程
Runnable timerTask = new MyTimerTask();
cheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
executorService.scheduleAtFixedRate(timerTask, 0, MyTimerTask.TimeInterval, TimeUnit.MILLISECONDS);
//数据库守护线程
Runnable mybatisTask = new MybatisTask();
ScheduledExecutorService executorService1 = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
executorService1.scheduleAtFixedRate(mybatisTask, 0, Config.MybatisInterval, TimeUnit.MILLISECONDS);
//alarm数据库守护线程
Runnable alarmMybatisTask = new AlarmMybatisTask();
ScheduledExecutorService executorService3 = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
executorService3.scheduleAtFixedRate(alarmMybatisTask, 0, Config.AlarmMybatisInterval, TimeUnit.MILLISECONDS);
//数据过期线程
Runnable invalidTask = new InvalidTask();
ScheduledExecutorService executorService2 = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
executorService2.scheduleAtFixedRate(invalidTask, 0, Config.InvalidInterval, TimeUnit.MILLISECONDS);
Java前端web线程
在程序MyWebSocket中设置1个web线程:
@ServerEndpoint(prefix = "netty-websocket")
@Component
public class MyWebSocket {
private static final Log log = LogFactory.getLog(MyWebSocket.class);
private ScheduledExecutorService executorService;
@OnOpen
public void onOpen(Session session, HttpHeaders headers, ParameterMap parameterMap) throws IOException {
System.out.println("new connection");
log.info("web socker new connection");
String paramValue = parameterMap.getParameter("paramKey");
System.out.println(paramValue);
//数据过期线程
executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
Runnable webSocketTask = new WebSocketTask(session);
executorService.scheduleAtFixedRate(webSocketTask, 0, Config.WebsocketInterval, TimeUnit.MILLISECONDS);
}
@OnClose
public void onClose(Session session) throws IOException {
System.out.println("one connection closed");
log.error("one connection closed");
executorService.shutdown();
}
}
WebSocketTask
public class WebSocketTask implements Runnable {
private static final Log log = LogFactory.getLog(WebSocketTask.class);
private int cycle = 1;
private Session session;
private boolean firstFlag = true;
private Msg.RouteProto routeProtoOrg;
public WebSocketTask(Session session) {
this.session = session;
}
public int getCycle() {
return this.cycle;
}
public void setCycle() {
if ((this.cycle - Config.CYCLE_MAX) >= 0) {
this.cycle = Config.CYCLE_MIN;
} else {
this.cycle += 1;
}
}
@Override
public void run() {
if (!FlagGlobal.flagMap.get(FlagTyepEnum.Init.getCode())) {
log.error("初始化未成功~,暂不启动websocketTask线程!");
return;
}
log.error("myWork start ...");
try {
int sendFlag = 0;
StringBuffer typeBuff = new StringBuffer();
//设置包头
Msg.MsgProto.Builder msgBuilder = Msg.MsgProto.newBuilder();
msgBuilder.setVersion(1);
msgBuilder.setPlatform(1);
msgBuilder.setCycle(this.getCycle());
msgBuilder.setTime(System.currentTimeMillis());
if (this.firstFlag) {
this.firstFlag = false;
this.routeProtoOrg = WebGlobal.webRoute;
//发送全量包
msgBuilder.setFlag(Config.FULL_STATUS);
msgBuilder.setType(WebSocketTyepEnum.Full.getCode());
msgBuilder.setRoute(WebGlobal.webRoute);
Msg.MsgProto msgProto = msgBuilder.build();
log.info("web send first full pkg....\n" + msgProto);
session.sendBinary(msgProto.toByteArray());
this.setCycle();
return;
}
if (FlagGlobal.flagMap.get(FlagTyepEnum.Full.getCode())) {
msgBuilder.setFlag(Config.FULL_STATUS);
msgBuilder.setType(WebSocketTyepEnum.Full.getCode());
msgBuilder.setRoute(WebGlobal.webRoute);
Msg.MsgProto msgProto = msgBuilder.build();
log.info("web send full pkg....\n" + msgProto);
session.sendBinary(msgProto.toByteArray());
FlagGlobal.flagMap.put(FlagTyepEnum.Full.getCode(), false);
this.setCycle();
return;
}
//进路信息模块
if (WebGlobal.webRoute != null) {
//webRoute中是最新周期包
Msg.RouteProto routeProto = WebGlobal.webRoute;
/**
*
* 取 消 包
*/
if (routeProto != null) {
//获得取消包protobuf:routeCancel
Map<String, Object> routeCancel = getCancelData_Route(routeProto);
if ((Integer) routeCancel.get("code") == Config.SUCC_CODE) {
sendFlag++;
Msg.MsgProto.Builder msgBuilder1 = Msg.MsgProto.newBuilder();
msgBuilder1.setRoute((Msg.RouteProto) routeCancel.get("data"));
msgBuilder1.setVersion(1);
msgBuilder1.setPlatform(1);
msgBuilder1.setCycle(this.getCycle());
msgBuilder1.setTime(System.currentTimeMillis());
msgBuilder1.setType(WebSocketTyepEnum.Route.getCode());
//取消包类型
msgBuilder1.setFlag(Config.CANCEL_STATUS);
Msg.MsgProto msgProto = msgBuilder1.build();
//发送前端
session.sendBinary(msgProto.toByteArray());
log.info("web send..cancel..\n" + msgProto);
this.setCycle();
}
/**
*
* 变 化 包
*/
Map<String, Object> routeRes = getChangeData_Route(routeProto);
if ((Integer) routeRes.get("code") == Config.SUCC_CODE) {
sendFlag++;
if (typeBuff.length() == 0) {
typeBuff.append(WebSocketTyepEnum.Route.getCode());
} else {
typeBuff.append("," + WebSocketTyepEnum.Route.getCode());
}
msgBuilder.setRoute((Msg.RouteProto) routeRes.get("data"));
}
}
this.routeProtoOrg = routeProto;
}
log.error("myWork sendFlag= ..." + sendFlag);
//最终给前端发送整体protobuf
if (sendFlag > 0) {
this.setCycle();
msgBuilder.setType(typeBuff.toString());
msgBuilder.setFlag(Config.CHG_STATUS);
Msg.MsgProto msgProto = msgBuilder.build();
log.info("web send....\n" + msgProto);
session.sendBinary(msgProto.toByteArray());
}
} catch (Exception e) {
log.error("myWork.error,", e);
}
}
/**
* 比较进路信息,得到变化包
*
* @param routeProto 新周期routeProto
* @return
*/
private Map<String, Object> getChangeData_Route(Msg.RouteProto routeProto) {
Map<String, Object> resp = new HashMap<String, Object>();
//上周期this.routeProtoOrg,新周期routeProto,比较:
Msg.RouteProto diffRoute = compareData(this.routeProtoOrg, routeProto);
if (diffRoute == null) {
resp.put("code", Config.ERR_CODE);
return resp;
}
resp.put("code", Config.SUCC_CODE);
resp.put("status", Config.CHG_STATUS);
resp.put("data", diffRoute);
return resp;
}
/**
* 比较进路信息,得到取消包
*
* @param routeProto 新周期routeProto
* @return
*/
public Map<String, Object> getCancelData_Route(Msg.RouteProto routeProto) {
Map<String, Object> resp = new HashMap<String, Object>();
//上周期this.routeProtoOrg,新周期routeProto,比较:
Msg.RouteProto diffRoute = cancelData(this.routeProtoOrg, routeProto);
if (diffRoute == null) {
resp.put("code", Config.ERR_CODE);
return resp;
}
resp.put("code", Config.SUCC_CODE);
//添加取消包配置CANCEL_STATUS
resp.put("cancel", Config.CANCEL_STATUS);
resp.put("data", diffRoute);
return resp;
}
/**
* 比较总进路信息上一次和这一次的包的不同
*
* @param last 上一周期
* @param now 新周期
* @return
*/
private Msg.RouteProto compareData(Msg.RouteProto last, Msg.RouteProto now) {
List<Msg.RouteInfo> diffList = compareRouteInfo(last.getListList(), now.getListList());
if (diffList.size() == 0) {
return null;
}
//新旧周期RouteInfo不相等,变化部分res
Msg.RouteProto.Builder res = Msg.RouteProto.newBuilder();
res.setNumber(diffList.size());
res.addAllList(diffList);
return res.build();
}
/**
* 比较总进路新旧周期,得到取消进路
*
* @param last 上一周期
* @param now 新周期
* @return
*/
public Msg.RouteProto cancelData(Msg.RouteProto last, Msg.RouteProto now) {
//比较新旧周期的proto的第二层list数据RouteInfo
List<Msg.RouteInfo> diffList1 = cancelRouteInfo(last.getListList(), now.getListList());
if (diffList1.size() == 0) {
return null;
}
//新旧周期RouteInfo不相等,变化部分res
Msg.RouteProto.Builder res = Msg.RouteProto.newBuilder();
res.setNumber(diffList1.size());
res.addAllList(diffList1);
return res.build();
}
/**
* 比较总进路中RouteInfo,获得取消进路
*
* @param old
* @param now
* @return
*/
public List<Msg.RouteInfo> cancelRouteInfo(List<Msg.RouteInfo> old, List<Msg.RouteInfo> now) {
//变化的RouteInfo
List<Msg.RouteInfo> different = new ArrayList<>();
//上周期的RouteInfo
List<Msg.RouteInfo> maxList = old;
//新周期的RouteInfo
List<Msg.RouteInfo> minList = now;
Map<Integer, Integer> map = new HashMap<>(maxList.size());
Map<Integer, Msg.RouteInfo> mapOrg = new HashMap<>(maxList.size());
Map<Integer, Msg.RouteInfo> mapDiff = new HashMap<>();
//遍历上一周期
for (Msg.RouteInfo routeInfo : maxList) {
//map存放上周期的RouteInfo
map.put(routeInfo.getRouteId(), 1);
//mapOrg存放上周期的RouteInfo
mapOrg.put(routeInfo.getRouteId(), routeInfo);
}
//遍历新周期的map
for (Msg.RouteInfo routeInfo : minList) {
/**
* 获取新周期minList的routeInfo.getRouteId(),判断该id是否在上周期map的key中:
* 如果该id在上周期,则不为空,将其id又put进map的key,value赋值为2。且continue,直到
* 该id不在上周期,则为空,将其id值put进mapDiff中。
* 旧:1(value:1)、2(value:1)、3(value:1)
* 新:1、2、4
*
*/
if (map.get(routeInfo.getRouteId()) != null) {
// map:1(value:2)、2(value:2)、3(value:1)
//3(value:1)取消了
map.put(routeInfo.getRouteId(), 2);
continue;
}
//id为4的放入mapDiff
mapDiff.put(routeInfo.getRouteId(), routeInfo);
}
/**
*
* 取消包
*/
if (map.size() > 0) {
//遍历map:1(value:2)、2(value:2)、3(value:1)
for (Map.Entry<Integer, Integer> entryCancel : map.entrySet()) {
//获取value为1的是取消的
if (entryCancel.getValue() == 1) {
Msg.RouteInfo.Builder routeCancel = Msg.RouteInfo.newBuilder();
routeCancel.setRouteId(entryCancel.getKey());
different.add(routeCancel.build());
}
}
}
return different;
}
/**
* 比较总进路中RouteInfo
*
* @param old
* @param now
* @return
*/
private List<Msg.RouteInfo> compareRouteInfo(List<Msg.RouteInfo> old, List<Msg.RouteInfo> now) {
//变化的RouteInfo
List<Msg.RouteInfo> different = new ArrayList<>();
//上周期的RouteInfo
List<Msg.RouteInfo> maxList = old;
//新周期的RouteInfo
List<Msg.RouteInfo> minList = now;
Map<Msg.RouteInfo, Integer> map = new HashMap<>(maxList.size());
Map<Integer, Msg.RouteInfo> mapOrg = new HashMap<>(maxList.size());
Map<Integer, Msg.RouteInfo> mapDiff = new HashMap<>();
//遍历上一周期
for (Msg.RouteInfo routeInfo : maxList) {
//map存放上周期的RouteInfo
map.put(routeInfo, 1);
//mapOrg存放上周期的RouteInfo
mapOrg.put(routeInfo.getRouteId(), routeInfo);
}
//遍历新周期的map
for (Msg.RouteInfo routeInfo : minList) {
//判断上周期的RouteInfo不为空
if (map.get(routeInfo) != null) {
//继续map存放新周期的RouteInfo,每次新周期来都有标志
map.put(routeInfo, 2);
continue;
}
//将新周期的routeInfo存入mapDiff
mapDiff.put(routeInfo.getRouteId(), routeInfo);
}
/**
*
* 变化包
*/
//遍历存有新周期信息的mapDiff
for (Map.Entry<Integer, Msg.RouteInfo> entry : mapDiff.entrySet()) {
//判断上周期mapOrg的key是否包含新周期的key
if (!mapOrg.containsKey(entry.getKey())) {
//若不包含,新周期中该key对应信息value为新的,将该信息add进变化的RouteInfo
different.add(entry.getValue());
}
//判断上周期mapOrg的key包含了新周期的key,比较同一key对应value的值
else {
Msg.RouteInfo.Builder builder = Msg.RouteInfo.newBuilder();
//同一key,取上周期的RouteInfo
Msg.RouteInfo orgRouteInfo = mapOrg.get(entry.getKey());
//同一key,取新周期的RouteInfo
Msg.RouteInfo nowRouteInfo = entry.getValue();
//set新周期进路id
builder.setRouteId(nowRouteInfo.getRouteId());
//其次,一一判断新周期nowRouteInfo的各个状态是否与上周期orgRouteInfo相等
if ((nowRouteInfo.getSectionCnt() - orgRouteInfo.getSectionCnt()) != 0) {
//不相等,set新周期的状态
builder.setSectionCnt(nowRouteInfo.getSectionCnt());
}
if ((nowRouteInfo.getSignalStatus() - orgRouteInfo.getSignalStatus()) != 0) {
builder.setSignalStatus(nowRouteInfo.getSignalStatus());
}
//比较routeInfo中的section的list集合(第三层proto最内层)
List<Msg.RouteSection> diffRouteSection = compareRouteSection(orgRouteInfo.getSectionsList(), nowRouteInfo.getSectionsList());
if (diffRouteSection.size() != 0) {
builder.addAllSections(diffRouteSection);
}
different.add(builder.build());
}
}
return different;
}
/**
* 比较单条进路内 区段信息 状态
*
* @param old
* @param now
* @return
*/
private List<Msg.RouteSection> compareRouteSection(List<Msg.RouteSection> old, List<Msg.RouteSection> now) {
List<Msg.RouteSection> sectionDifferent = new ArrayList<>();
Map<Msg.RouteSection, Integer> sectionMap = new HashMap<>(old.size());
Map<Integer, Msg.RouteSection> sectionMapOrg = new HashMap<>(now.size());
Map<Integer, Msg.RouteSection> sectionMapDiff = new HashMap<>();
//旧周期
for (Msg.RouteSection routeSection : old) {
sectionMap.put(routeSection, 1);
sectionMapOrg.put(routeSection.getSectionNr(), routeSection);
}
//新周期
for (Msg.RouteSection sectionList : now) {
if (sectionMap.get(sectionList) != null) {
sectionMap.put(sectionList, 2);
continue;
}
sectionMapDiff.put(sectionList.getSectionNr(), sectionList);
}
//遍历新周期
for (Map.Entry<Integer, Msg.RouteSection> entry : sectionMapDiff.entrySet()) {
if (!sectionMapOrg.containsKey(entry.getKey())) {
sectionDifferent.add(entry.getValue());
} else {
Msg.RouteSection.Builder sbuilder = Msg.RouteSection.newBuilder();
//旧
Msg.RouteSection orgSection = sectionMapOrg.get(entry.getKey());
//新
Msg.RouteSection nowSection = entry.getValue();
sbuilder.setId(nowSection.getId());
//sbuilder.setSectionNr(nowSection.getSectionNr());
if ((nowSection.getSectionNr() - orgSection.getSectionNr()) != 0) {
sbuilder.setSectionNr(nowSection.getSectionNr());
}
if ((nowSection.getStatus() - orgSection.getStatus()) != 0) {
sbuilder.setStatus(nowSection.getStatus());
}
sectionDifferent.add(sbuilder.build());
}
}
return sectionDifferent;
}
}
web发送数据
测试地址: http://www.websocket-test.com/
对应在application.yml中配置websocket测试地址和端口: