| | |
| | | * 与原有的轮询查询类互补,专注于在线设备的持续监控 |
| | | */ |
| | | public class lunxunzaixian { |
| | | private static final AtomicBoolean isRunning = new AtomicBoolean(false); |
| | | private static final AtomicBoolean isPaused = new AtomicBoolean(false); |
| | | private static final AtomicBoolean shouldStop = new AtomicBoolean(false); |
| | | private static Thread onlinePollingThread; |
| | | |
| | | // 可配置的轮询参数(不再是final) |
| | | private static int cycleInterval = 60000; // 完整轮询周期间隔:60秒 |
| | | private static int slotInterval = 200; // 卡槽间查询间隔:200毫秒 |
| | | |
| | | // 卡槽相关常量 |
| | | private static final int MIN_SLOT = 1; |
| | | private static final int MAX_SLOT = 60; |
| | | |
| | | // 性能优化配置 |
| | | private static final int BATCH_SIZE = 5; // 批量查询大小 |
| | | private static int consecutiveFailures = 0; |
| | | private static final int MAX_CONSECUTIVE_FAILURES = 3; |
| | | |
| | | /** |
| | | * 启动在线轮询 - 优化版本 |
| | | * @return true-启动成功, false-启动失败 |
| | | */ |
| | | public static boolean startOnlinePolling() { |
| | | if (isRunning.get()) { |
| | | SystemDebugDialog.appendAsciiData("Online polling is already in progress"); |
| | | return true; |
| | | } |
| | | |
| | | // 检查串口连接状态 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口未连接,无法启动在线轮询"); |
| | | return false; |
| | | } |
| | | |
| | | isRunning.set(true); |
| | | isPaused.set(false); |
| | | shouldStop.set(false); |
| | | consecutiveFailures = 0; |
| | | |
| | | try { |
| | | onlinePollingThread = new Thread(new OnlinePollingTask(), "Online-Polling-Thread"); |
| | | onlinePollingThread.setDaemon(true); |
| | | onlinePollingThread.start(); |
| | | System.out.println("在线轮询已启动,周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); |
| | | return true; |
| | | } catch (Exception e) { |
| | | System.err.println("启动在线轮询线程时发生异常: " + e.getMessage()); |
| | | isRunning.set(false); |
| | | shouldStop.set(true); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 停止在线轮询 - 修复版本 |
| | | * @return true-停止成功, false-停止失败 |
| | | */ |
| | | public static boolean stopOnlinePolling() { |
| | | if (!isRunning.get()) { |
| | | System.out.println("在线轮询未在运行"); |
| | | return false; |
| | | } |
| | | |
| | | shouldStop.set(true); |
| | | isRunning.set(false); |
| | | isPaused.set(false); |
| | | |
| | | if (onlinePollingThread != null) { |
| | | onlinePollingThread.interrupt(); |
| | | try { |
| | | onlinePollingThread.join(3000); // 等待3秒 |
| | | // 检查线程是否还在运行 |
| | | if (onlinePollingThread.isAlive()) { |
| | | System.err.println("在线轮询线程未在3秒内停止,标记为守护线程并忽略"); |
| | | // 不强制停止,而是确保它是守护线程 |
| | | onlinePollingThread.setDaemon(true); |
| | | } |
| | | } catch (InterruptedException e) { |
| | | System.err.println("停止在线轮询时被中断: " + e.getMessage()); |
| | | Thread.currentThread().interrupt(); |
| | | } catch (Exception e) { |
| | | System.err.println("停止在线轮询线程时发生异常: " + e.getMessage()); |
| | | } finally { |
| | | onlinePollingThread = null; |
| | | } |
| | | } |
| | | |
| | | shouldStop.set(false); |
| | | System.out.println("在线轮询已停止"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 暂停在线轮询 |
| | | * @return true-暂停成功, false-暂停失败 |
| | | */ |
| | | public static boolean pauseOnlinePolling() { |
| | | if (!isRunning.get()) { |
| | | System.out.println("在线轮询未在运行,无法暂停"); |
| | | return false; |
| | | } |
| | | |
| | | if (isPaused.get()) { |
| | | System.out.println("在线轮询已经处于暂停状态"); |
| | | return false; |
| | | } |
| | | |
| | | isPaused.set(true); |
| | | System.out.println("在线轮询已暂停"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 恢复在线轮询 |
| | | * @return true-恢复成功, false-恢复失败 |
| | | */ |
| | | public static boolean resumeOnlinePolling() { |
| | | if (!isRunning.get()) { |
| | | System.out.println("在线轮询未在运行,无法恢复"); |
| | | return false; |
| | | } |
| | | |
| | | if (!isPaused.get()) { |
| | | System.out.println("在线轮询未处于暂停状态"); |
| | | return false; |
| | | } |
| | | |
| | | // 恢复前检查串口连接 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口未连接,无法恢复在线轮询"); |
| | | return false; |
| | | } |
| | | |
| | | isPaused.set(false); |
| | | synchronized (lunxunzaixian.class) { |
| | | lunxunzaixian.class.notifyAll(); // 唤醒等待的线程 |
| | | } |
| | | System.out.println("在线轮询已恢复"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 检查在线轮询状态 |
| | | * @return true-正在运行, false-已停止 |
| | | */ |
| | | public static boolean isOnlinePolling() { |
| | | return isRunning.get(); |
| | | } |
| | | |
| | | /** |
| | | * 检查是否暂停 |
| | | * @return true-已暂停, false-未暂停 |
| | | */ |
| | | public static boolean isOnlinePaused() { |
| | | return isPaused.get(); |
| | | } |
| | | |
| | | /** |
| | | * 重新启动在线轮询 |
| | | * @return true-重启成功, false-重启失败 |
| | | */ |
| | | public static boolean restartOnlinePolling() { |
| | | stopOnlinePolling(); |
| | | |
| | | // 等待一小段时间确保线程完全停止 |
| | | try { |
| | | Thread.sleep(200); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | |
| | | return startOnlinePolling(); |
| | | } |
| | | |
| | | /** |
| | | * 设置轮询间隔参数 |
| | | * @param cycleMs 完整轮询周期间隔(毫秒) |
| | | * @param slotMs 卡槽间查询间隔(毫秒) |
| | | */ |
| | | public static void setPollingIntervals(int cycleMs, int slotMs) { |
| | | cycleInterval = Math.max(cycleMs, 1000); // 最小1秒 |
| | | slotInterval = Math.max(slotMs, 50); // 最小50毫秒 |
| | | System.out.println("在线轮询间隔已设置 - 周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); |
| | | |
| | | // 如果正在运行,重新启动以应用新的间隔 |
| | | if (isRunning.get()) { |
| | | restartOnlinePolling(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取当前轮询间隔配置 |
| | | * @return 间隔配置字符串 |
| | | */ |
| | | public static String getPollingIntervals() { |
| | | return String.format("周期间隔: %dms, 卡槽间隔: %dms", cycleInterval, slotInterval); |
| | | } |
| | | |
| | | /** |
| | | * 获取在线轮询统计信息 |
| | | * @return 统计信息字符串 |
| | | */ |
| | | public static String getOnlinePollingStats() { |
| | | int totalSlots = MAX_SLOT - MIN_SLOT + 1; |
| | | int cardSlots = countCardSlots(); |
| | | |
| | | String status; |
| | | if (!isRunning.get()) { |
| | | status = "已停止"; |
| | | } else if (isPaused.get()) { |
| | | status = "已暂停"; |
| | | } else { |
| | | status = "运行中"; |
| | | } |
| | | |
| | | return String.format("在线轮询状态: %s, 有卡卡槽: %d/%d, 周期间隔: %ds, 卡槽间隔: %dms", |
| | | status, cardSlots, totalSlots, cycleInterval/1000, slotInterval); |
| | | } |
| | | |
| | | /** |
| | | * 统计有卡的卡槽数量 |
| | | * @return 有卡的卡槽数量 |
| | | */ |
| | | private static int countCardSlots() { |
| | | if (SlotManager.slotArray == null) { |
| | | return 0; |
| | | } |
| | | |
| | | int count = 0; |
| | | for (Fkj slot : SlotManager.slotArray) { |
| | | if (slot != null && "1".equals(slot.getHasCard())) { |
| | | count++; |
| | | } |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | /** |
| | | * 带重试的串口连接检查 |
| | | */ |
| | | private static boolean checkSerialConnectionWithRetry() { |
| | | for (int i = 0; i < 3; i++) { |
| | | if (lunxun.checkSerialConnection()) { |
| | | return true; |
| | | } |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | return false; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 在线轮询任务内部类 - 优化版本 |
| | | * 专门轮询有卡的卡槽,优化资源使用 |
| | | */ |
| | | private static class OnlinePollingTask implements Runnable { |
| | | @Override |
| | | public void run() { |
| | | System.out.println("在线轮询线程开始运行"); |
| | | |
| | | while (isRunning.get() && !Thread.currentThread().isInterrupted() && !shouldStop.get()) { |
| | | try { |
| | | // 检查是否暂停 |
| | | if (isPaused.get()) { |
| | | synchronized (lunxunzaixian.class) { |
| | | while (isPaused.get() && isRunning.get() && !shouldStop.get()) { |
| | | lunxunzaixian.class.wait(1000); // 等待1秒或直到被唤醒 |
| | | } |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | // 检查串口连接状态 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口连接断开,暂停在线轮询"); |
| | | pauseOnlinePolling(); |
| | | continue; |
| | | } |
| | | |
| | | // 执行一轮有卡卡槽的轮询 |
| | | if (pollCardSlotsOptimized()) { |
| | | consecutiveFailures = 0; // 重置连续失败计数 |
| | | } else { |
| | | consecutiveFailures++; |
| | | if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { |
| | | System.err.println("连续失败次数过多,暂停在线轮询"); |
| | | pauseOnlinePolling(); |
| | | } |
| | | } |
| | | |
| | | // 等待完整周期间隔 |
| | | Thread.sleep(cycleInterval); |
| | | |
| | | } catch (InterruptedException e) { |
| | | System.out.println("在线轮询线程被中断"); |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } catch (Exception e) { |
| | | System.err.println("在线轮询过程中发生异常: " + e.getMessage()); |
| | | consecutiveFailures++; |
| | | |
| | | // 发生异常时等待一段时间再继续 |
| | | try { |
| | | Thread.sleep(5000); |
| | | } catch (InterruptedException ie) { |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | System.out.println("在线轮询线程结束运行"); |
| | | } |
| | | |
| | | /** |
| | | * 优化版本:批量轮询有卡卡槽 |
| | | * @return true-轮询成功, false-轮询失败 |
| | | */ |
| | | private boolean pollCardSlotsOptimized() { |
| | | if (SlotManager.slotArray == null) { |
| | | System.err.println("卡槽数组未初始化"); |
| | | return false; |
| | | } |
| | | |
| | | List<Integer> cardSlots = new ArrayList<>(); |
| | | |
| | | // 第一阶段:收集所有有卡卡槽 |
| | | for (int i = 0; i < SlotManager.slotArray.length; i++) { |
| | | if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { |
| | | break; |
| | | } |
| | | |
| | | Fkj slot = SlotManager.slotArray[i]; |
| | | if (slot != null && "1".equals(slot.getHasCard())) { |
| | | cardSlots.add(i + 1); |
| | | } |
| | | } |
| | | |
| | | if (cardSlots.isEmpty()) { |
| | | if (lunxun.DEBUG_ENABLED) { |
| | | System.out.println("没有找到有卡的卡槽"); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | int polledCount = 0; |
| | | int totalCardSlots = cardSlots.size(); |
| | | |
| | | // 第二阶段:批量查询有卡卡槽 |
| | | for (int i = 0; i < cardSlots.size(); i += BATCH_SIZE) { |
| | | if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { |
| | | break; |
| | | } |
| | | |
| | | int end = Math.min(i + BATCH_SIZE, cardSlots.size()); |
| | | List<Integer> batch = cardSlots.subList(i, end); |
| | | |
| | | // 批次内查询 |
| | | for (int slotNumber : batch) { |
| | | if (sendQueryToCardSlot(slotNumber)) { |
| | | polledCount++; |
| | | } |
| | | } |
| | | |
| | | // 批次间间隔 |
| | | if (end < cardSlots.size()) { |
| | | try { |
| | | Thread.sleep(slotInterval * BATCH_SIZE); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (polledCount > 0 && lunxun.DEBUG_ENABLED) { |
| | | System.out.println("在线轮询完成,成功查询 " + polledCount + "/" + totalCardSlots + " 个有卡卡槽"); |
| | | } |
| | | |
| | | return polledCount > 0; |
| | | } |
| | | |
| | | /** |
| | | * 向指定有卡卡槽发送查询指令 |
| | | * @param slotNumber 卡槽编号 |
| | | * @return true-发送成功, false-发送失败 |
| | | */ |
| | | private boolean sendQueryToCardSlot(int slotNumber) { |
| | | try { |
| | | // 使用原有的立即查询功能 |
| | | boolean result = lunxun.sendImmediateQuery(slotNumber); |
| | | |
| | | if (result) { |
| | | // 记录调试信息(减少输出频率) |
| | | if (lunxun.DEBUG_ENABLED && (slotNumber == 1 || slotNumber % 10 == 0)) { |
| | | System.out.println("在线轮询 - 查询有卡卡槽 " + slotNumber); |
| | | } |
| | | return true; |
| | | } else { |
| | | System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 失败"); |
| | | return false; |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 手动触发立即轮询(不等待周期)- 优化版本 |
| | | * @return 成功查询的卡槽数量 |
| | | */ |
| | | public static int triggerImmediatePolling() { |
| | | if (!isRunning.get() || isPaused.get()) { |
| | | System.err.println("在线轮询未运行或已暂停,无法立即轮询"); |
| | | return 0; |
| | | } |
| | | |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口未连接,无法执行立即轮询"); |
| | | return 0; |
| | | } |
| | | |
| | | System.out.println("开始立即轮询有卡卡槽..."); |
| | | |
| | | OnlinePollingTask task = new OnlinePollingTask(); |
| | | |
| | | // 使用新的批量轮询方法 |
| | | int cardSlotCount = countCardSlots(); |
| | | |
| | | // 在新线程中执行立即轮询,避免阻塞当前线程 |
| | | Thread immediateThread = new Thread(() -> { |
| | | try { |
| | | task.pollCardSlotsOptimized(); |
| | | } catch (Exception e) { |
| | | System.err.println("立即轮询过程中发生异常: " + e.getMessage()); |
| | | } |
| | | }, "Immediate-Online-Polling"); |
| | | |
| | | immediateThread.setDaemon(true); |
| | | immediateThread.start(); |
| | | |
| | | return cardSlotCount; |
| | | } |
| | | |
| | | /** |
| | | * 设置在线轮询暂停状态(供其他类调用) |
| | | * @param paused true-暂停轮询, false-恢复轮询 |
| | | * @return true-设置成功, false-设置失败 |
| | | */ |
| | | public static boolean setOnlinePollingPaused(boolean paused) { |
| | | if (!isRunning.get()) { |
| | | System.out.println("在线轮询未在运行,无法设置暂停状态"); |
| | | return false; |
| | | } |
| | | |
| | | if (paused) { |
| | | return pauseOnlinePolling(); |
| | | } else { |
| | | return resumeOnlinePolling(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取性能统计信息 |
| | | */ |
| | | public static String getPerformanceStats() { |
| | | return String.format("批量大小: %d, 周期间隔: %dms, 卡槽间隔: %dms", |
| | | BATCH_SIZE, cycleInterval, slotInterval); |
| | | } |
| | | private static final AtomicBoolean isRunning = new AtomicBoolean(false); |
| | | private static final AtomicBoolean isPaused = new AtomicBoolean(false); |
| | | private static final AtomicBoolean shouldStop = new AtomicBoolean(false); |
| | | private static Thread onlinePollingThread; |
| | | |
| | | // 可配置的轮询参数(不再是final) |
| | | private static int cycleInterval = 120000; // 完整轮询周期间隔:60秒 |
| | | private static int slotInterval = 200; // 卡槽间查询间隔:500毫秒 |
| | | |
| | | // 卡槽相关常量 |
| | | private static final int MIN_SLOT = 1; |
| | | private static final int MAX_SLOT = 60; |
| | | |
| | | // 性能优化配置 |
| | | private static final int BATCH_SIZE = 5; // 批量查询大小 |
| | | private static int consecutiveFailures = 0; |
| | | private static final int MAX_CONSECUTIVE_FAILURES = 3; |
| | | |
| | | /** |
| | | * 启动在线轮询 - 优化版本 |
| | | * @return true-启动成功, false-启动失败 |
| | | */ |
| | | public static boolean startOnlinePolling() { |
| | | if (isRunning.get()) { |
| | | SystemDebugDialog.appendAsciiData("Online polling is already in progress"); |
| | | return true; |
| | | } |
| | | |
| | | // 检查串口连接状态 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口未连接,无法启动在线轮询"); |
| | | return false; |
| | | } |
| | | |
| | | isRunning.set(true); |
| | | isPaused.set(false); |
| | | shouldStop.set(false); |
| | | consecutiveFailures = 0; |
| | | |
| | | try { |
| | | onlinePollingThread = new Thread(new OnlinePollingTask(), "Online-Polling-Thread"); |
| | | onlinePollingThread.setDaemon(true); |
| | | onlinePollingThread.start(); |
| | | //System.out.println("在线轮询已启动,周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); |
| | | return true; |
| | | } catch (Exception e) { |
| | | System.err.println("启动在线轮询线程时发生异常: " + e.getMessage()); |
| | | isRunning.set(false); |
| | | shouldStop.set(true); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 停止在线轮询 - 修复版本 |
| | | * @return true-停止成功, false-停止失败 |
| | | */ |
| | | public static boolean stopOnlinePolling() { |
| | | if (!isRunning.get()) { |
| | | //System.out.println("在线轮询未在运行"); |
| | | return false; |
| | | } |
| | | |
| | | shouldStop.set(true); |
| | | isRunning.set(false); |
| | | isPaused.set(false); |
| | | |
| | | if (onlinePollingThread != null) { |
| | | onlinePollingThread.interrupt(); |
| | | try { |
| | | onlinePollingThread.join(3000); // 等待3秒 |
| | | // 检查线程是否还在运行 |
| | | if (onlinePollingThread.isAlive()) { |
| | | System.err.println("在线轮询线程未在3秒内停止,标记为守护线程并忽略"); |
| | | // 不强制停止,而是确保它是守护线程 |
| | | onlinePollingThread.setDaemon(true); |
| | | } |
| | | } catch (InterruptedException e) { |
| | | System.err.println("停止在线轮询时被中断: " + e.getMessage()); |
| | | Thread.currentThread().interrupt(); |
| | | } catch (Exception e) { |
| | | System.err.println("停止在线轮询线程时发生异常: " + e.getMessage()); |
| | | } finally { |
| | | onlinePollingThread = null; |
| | | } |
| | | } |
| | | |
| | | shouldStop.set(false); |
| | | //System.out.println("在线轮询已停止"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 暂停在线轮询 |
| | | * @return true-暂停成功, false-暂停失败 |
| | | */ |
| | | public static boolean pauseOnlinePolling() { |
| | | if (!isRunning.get()) { |
| | | //System.out.println("在线轮询未在运行,无法暂停"); |
| | | return false; |
| | | } |
| | | |
| | | if (isPaused.get()) { |
| | | //System.out.println("在线轮询已经处于暂停状态"); |
| | | return false; |
| | | } |
| | | |
| | | isPaused.set(true); |
| | | //System.out.println("在线轮询已暂停"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 恢复在线轮询 |
| | | * @return true-恢复成功, false-恢复失败 |
| | | */ |
| | | public static boolean resumeOnlinePolling() { |
| | | if (!isRunning.get()) { |
| | | //System.out.println("在线轮询未在运行,无法恢复"); |
| | | return false; |
| | | } |
| | | |
| | | if (!isPaused.get()) { |
| | | //System.out.println("在线轮询未处于暂停状态"); |
| | | return false; |
| | | } |
| | | |
| | | // 恢复前检查串口连接 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口未连接,无法恢复在线轮询"); |
| | | return false; |
| | | } |
| | | |
| | | isPaused.set(false); |
| | | synchronized (lunxunzaixian.class) { |
| | | lunxunzaixian.class.notifyAll(); // 唤醒等待的线程 |
| | | } |
| | | //System.out.println("在线轮询已恢复"); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 检查在线轮询状态 |
| | | * @return true-正在运行, false-已停止 |
| | | */ |
| | | public static boolean isOnlinePolling() { |
| | | return isRunning.get(); |
| | | } |
| | | |
| | | /** |
| | | * 检查是否暂停 |
| | | * @return true-已暂停, false-未暂停 |
| | | */ |
| | | public static boolean isOnlinePaused() { |
| | | return isPaused.get(); |
| | | } |
| | | |
| | | /** |
| | | * 重新启动在线轮询 |
| | | * @return true-重启成功, false-重启失败 |
| | | */ |
| | | public static boolean restartOnlinePolling() { |
| | | stopOnlinePolling(); |
| | | |
| | | // 等待一小段时间确保线程完全停止 |
| | | try { |
| | | Thread.sleep(200); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | |
| | | return startOnlinePolling(); |
| | | } |
| | | |
| | | /** |
| | | * 设置轮询间隔参数 |
| | | * @param cycleMs 完整轮询周期间隔(毫秒) |
| | | * @param slotMs 卡槽间查询间隔(毫秒) |
| | | */ |
| | | public static void setPollingIntervals(int cycleMs, int slotMs) { |
| | | cycleInterval = Math.max(cycleMs, 1000); // 最小1秒 |
| | | slotInterval = Math.max(slotMs, 50); // 最小50毫秒 |
| | | //System.out.println("在线轮询间隔已设置 - 周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); |
| | | |
| | | // 如果正在运行,重新启动以应用新的间隔 |
| | | if (isRunning.get()) { |
| | | restartOnlinePolling(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取当前轮询间隔配置 |
| | | * @return 间隔配置字符串 |
| | | */ |
| | | public static String getPollingIntervals() { |
| | | return String.format("周期间隔: %dms, 卡槽间隔: %dms", cycleInterval, slotInterval); |
| | | } |
| | | |
| | | /** |
| | | * 获取在线轮询统计信息 |
| | | * @return 统计信息字符串 |
| | | */ |
| | | public static String getOnlinePollingStats() { |
| | | int totalSlots = MAX_SLOT - MIN_SLOT + 1; |
| | | int cardSlots = countCardSlots(); |
| | | |
| | | String status; |
| | | if (!isRunning.get()) { |
| | | status = "已停止"; |
| | | } else if (isPaused.get()) { |
| | | status = "已暂停"; |
| | | } else { |
| | | status = "运行中"; |
| | | } |
| | | |
| | | return String.format("在线轮询状态: %s, 有卡卡槽: %d/%d, 周期间隔: %ds, 卡槽间隔: %dms", |
| | | status, cardSlots, totalSlots, cycleInterval/1000, slotInterval); |
| | | } |
| | | |
| | | /** |
| | | * 统计有卡的卡槽数量 |
| | | * @return 有卡的卡槽数量 |
| | | */ |
| | | private static int countCardSlots() { |
| | | if (SlotManager.slotArray == null) { |
| | | return 0; |
| | | } |
| | | |
| | | int count = 0; |
| | | for (Fkj slot : SlotManager.slotArray) { |
| | | if (slot != null && "1".equals(slot.getHasCard())) { |
| | | count++; |
| | | } |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | /** |
| | | * 带重试的串口连接检查 |
| | | */ |
| | | private static boolean checkSerialConnectionWithRetry() { |
| | | for (int i = 0; i < 3; i++) { |
| | | if (lunxun.checkSerialConnection()) { |
| | | return true; |
| | | } |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | return false; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 在线轮询任务内部类 - 优化版本 |
| | | * 专门轮询有卡的卡槽,优化资源使用 |
| | | */ |
| | | private static class OnlinePollingTask implements Runnable { |
| | | @Override |
| | | public void run() { |
| | | //System.out.println("在线轮询线程开始运行"); |
| | | |
| | | while (isRunning.get() && !Thread.currentThread().isInterrupted() && !shouldStop.get()) { |
| | | try { |
| | | // 检查是否暂停 |
| | | if (isPaused.get()) { |
| | | synchronized (lunxunzaixian.class) { |
| | | while (isPaused.get() && isRunning.get() && !shouldStop.get()) { |
| | | lunxunzaixian.class.wait(1000); // 等待1秒或直到被唤醒 |
| | | } |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | // 检查串口连接状态 |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口连接断开,暂停在线轮询"); |
| | | pauseOnlinePolling(); |
| | | continue; |
| | | } |
| | | |
| | | // 执行一轮有卡卡槽的轮询 |
| | | if (pollCardSlotsOptimized()) { |
| | | consecutiveFailures = 0; // 重置连续失败计数 |
| | | } else { |
| | | consecutiveFailures++; |
| | | if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { |
| | | System.err.println("lunxunzaixian连续失败次数过多,暂停在线轮询"); |
| | | pauseOnlinePolling(); |
| | | } |
| | | } |
| | | |
| | | // 等待完整周期间隔 |
| | | Thread.sleep(cycleInterval); |
| | | |
| | | } catch (InterruptedException e) { |
| | | //System.out.println("在线轮询线程被中断"); |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } catch (Exception e) { |
| | | System.err.println("在线轮询过程中发生异常: " + e.getMessage()); |
| | | consecutiveFailures++; |
| | | |
| | | // 发生异常时等待一段时间再继续 |
| | | try { |
| | | Thread.sleep(5000); |
| | | } catch (InterruptedException ie) { |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | //System.out.println("在线轮询线程结束运行"); |
| | | } |
| | | |
| | | /** |
| | | * 优化版本:批量轮询有卡卡槽 |
| | | * @return true-轮询成功, false-轮询失败 |
| | | */ |
| | | private boolean pollCardSlotsOptimized() { |
| | | if (SlotManager.slotArray == null) { |
| | | System.err.println("卡槽数组未初始化"); |
| | | return false; |
| | | } |
| | | |
| | | List<Integer> cardSlots = new ArrayList<>(); |
| | | |
| | | // 第一阶段:收集所有有卡卡槽 |
| | | for (int i = 0; i < SlotManager.slotArray.length; i++) { |
| | | if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { |
| | | break; |
| | | } |
| | | |
| | | Fkj slot = SlotManager.slotArray[i]; |
| | | if (slot != null && "1".equals(slot.getHasCard())) { |
| | | cardSlots.add(i + 1); |
| | | } |
| | | } |
| | | |
| | | if (cardSlots.isEmpty()) { |
| | | if (lunxun.DEBUG_ENABLED) { |
| | | //System.out.println("没有找到有卡的卡槽"); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | int polledCount = 0; |
| | | int totalCardSlots = cardSlots.size(); |
| | | |
| | | // 第二阶段:批量查询有卡卡槽 - 修复:每个卡槽间都有间隔 |
| | | for (int i = 0; i < cardSlots.size(); i += BATCH_SIZE) { |
| | | if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { |
| | | break; |
| | | } |
| | | |
| | | int end = Math.min(i + BATCH_SIZE, cardSlots.size()); |
| | | List<Integer> batch = cardSlots.subList(i, end); |
| | | |
| | | // 批次内查询 - 修复:每个卡槽间添加间隔 |
| | | for (int j = 0; j < batch.size(); j++) { |
| | | int slotNumber = batch.get(j); |
| | | |
| | | if (sendQueryToCardSlot(slotNumber)) { |
| | | polledCount++; |
| | | } |
| | | |
| | | // 重要修复:每个卡槽查询后等待指定间隔(最后一个卡槽除外) |
| | | if (j < batch.size() - 1) { |
| | | try { |
| | | Thread.sleep(slotInterval); // 卡槽间间隔 |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 批次间间隔(保持原有逻辑) |
| | | if (end < cardSlots.size()) { |
| | | try { |
| | | Thread.sleep(slotInterval * BATCH_SIZE); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (polledCount > 0 && lunxun.DEBUG_ENABLED) { |
| | | System.out.println("在线轮询完成,成功查询 " + polledCount + "/" + totalCardSlots + " 个有卡卡槽"); |
| | | } |
| | | |
| | | return polledCount > 0; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向指定有卡卡槽发送查询指令 |
| | | * @param slotNumber 卡槽编号 |
| | | * @return true-发送成功, false-发送失败 |
| | | */ |
| | | private boolean sendQueryToCardSlot(int slotNumber) { |
| | | try { |
| | | // 使用原有的立即查询功能 |
| | | boolean result = lunxun.sendImmediateQuery(slotNumber); |
| | | |
| | | if (result) { |
| | | // 记录调试信息(减少输出频率) |
| | | if (lunxun.DEBUG_ENABLED && (slotNumber == 1 || slotNumber % 10 == 0)) { |
| | | //System.out.println("在线轮询 - 查询有卡卡槽 " + slotNumber); |
| | | } |
| | | return true; |
| | | } else { |
| | | System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 失败"); |
| | | return false; |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 手动触发立即轮询(不等待周期)- 优化版本 |
| | | * @return 成功查询的卡槽数量 |
| | | */ |
| | | public static int triggerImmediatePolling() { |
| | | if (!isRunning.get() || isPaused.get()) { |
| | | System.err.println("在线轮询未运行或已暂停,无法立即轮询"); |
| | | return 0; |
| | | } |
| | | |
| | | if (!checkSerialConnectionWithRetry()) { |
| | | System.err.println("串口未连接,无法执行立即轮询"); |
| | | return 0; |
| | | } |
| | | |
| | | //System.out.println("开始立即轮询有卡卡槽..."); |
| | | |
| | | OnlinePollingTask task = new OnlinePollingTask(); |
| | | |
| | | // 使用新的批量轮询方法 |
| | | int cardSlotCount = countCardSlots(); |
| | | |
| | | // 在新线程中执行立即轮询,避免阻塞当前线程 |
| | | Thread immediateThread = new Thread(() -> { |
| | | try { |
| | | task.pollCardSlotsOptimized(); |
| | | } catch (Exception e) { |
| | | System.err.println("立即轮询过程中发生异常: " + e.getMessage()); |
| | | } |
| | | }, "Immediate-Online-Polling"); |
| | | |
| | | immediateThread.setDaemon(true); |
| | | immediateThread.start(); |
| | | |
| | | return cardSlotCount; |
| | | } |
| | | |
| | | /** |
| | | * 设置在线轮询暂停状态(供其他类调用) |
| | | * @param paused true-暂停轮询, false-恢复轮询 |
| | | * @return true-设置成功, false-设置失败 |
| | | */ |
| | | public static boolean setOnlinePollingPaused(boolean paused) { |
| | | if (!isRunning.get()) { |
| | | //System.out.println("在线轮询未在运行,无法设置暂停状态"); |
| | | return false; |
| | | } |
| | | |
| | | if (paused) { |
| | | return pauseOnlinePolling(); |
| | | } else { |
| | | return resumeOnlinePolling(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取性能统计信息 |
| | | */ |
| | | public static String getPerformanceStats() { |
| | | return String.format("批量大小: %d, 周期间隔: %dms, 卡槽间隔: %dms", |
| | | BATCH_SIZE, cycleInterval, slotInterval); |
| | | } |
| | | } |