今天调试项目程序,涉及 6000 台表单线程进行抄读,平均每个表抄读要5秒钟,每天想抄读多次。
算下来 6000 * 5 = 30000 s = 500 min ≈ 8.3 hour
这样是绝对不行的,于是我想做成多线程抄表,通过netty的 ctx.executor().schedule()方法启动定时任务。
可是调试的时候发现下发抄表指令时,上报数据上不来,我和项目经理还有团队大佬研究了半天,还是没有解决。
- 后来经过调试我才发现,是因为我在ctx.executor().schedule()启动定时任务会附加在netty 的EventLoop进程中,而这个进程则是在处理抄表的进程,而且我还在定时抄表过程中用了sleep方法,sleep方法会阻塞当前线程的运行,所以由于一直执行抄表线程,上报数据当然没机会处理了。
for (MeterInfo meterInfo : materInfoList) {
Map<String, Object> map2 = new HashMap<>(3);
String meterCode = meterInfo.getMeterCode();
String factoryCode = FactoryCode.codeOf(meterInfo.getManufactureName());
if (Objects.nonNull(meterCode) && Objects.nonNull(factoryCode)) {
READING_METER.put(meterCode, identifier);
// 设置当前抄表厂商
READ_FACTORY.put(meterCode, FactoryCode.codeOfFactory(meterInfo.getManufactureName()));
LOGGER.info("{}|{}|{}|{}|{}", S_FREE, identifier, "READ METER", meterCode, meterInfo.getManufactureName());
map2.put(FieldKey.METER_CODE, meterCode);
map2.put(FieldKey.FIRM_CODE, factoryCode);
ObjectNode readMeter = CmdBuilder.builder().getCmdObjectNode(METER_READ.name(), identifier, map2);
ctx.writeAndFlush(new FramePacket(readMeter, framePacket.getSocketAddress(), null, ctx));
Thread.sleep(3 * 1000);
READING_SUCCESS.remove(meterCode);
}
}
所以解决方案为:
- 采用其他方式开启定时任务,而不是采用阻塞方式。
- 去掉sleep方式,用非阻塞定时器控制时序逻辑。
总结一句话:慎用sleep() 啊