张世豪
昨天 8f8eed75beb5bb9b66f2a87de856f2dbf11e6ffe
src/chushihua/lunxun.java
@@ -3,15 +3,22 @@
import chuankou.Sendmsg;
import home.MachineConfig;
import publicway.QueryData;
import xitongshezhi.Fkj;
import xitongshezhi.SystemDebugDialog;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
 * 轮询查询类
 * 轮询查询类 - 优化版本
 * 用于定时向所有卡槽发送查询指令
 * 支持暂停和恢复功能,检查串口连接状态
 */
public class lunxun {
    private static volatile boolean isRunning = false;
    private static volatile boolean isPaused = false;
    private static final AtomicBoolean shouldStop = new AtomicBoolean(false);
    private static Thread pollingThread;
    private static int pollingInterval = 100; // 默认轮询间隔
    
@@ -24,8 +31,14 @@
    private static long lastSerialCheckTime = 0;
    private static boolean serialConnected = false;
    
    // 性能优化:查询指令缓存
    private static final Map<Integer, String> queryCommandCache = new ConcurrentHashMap<>();
    // 调试模式控制
    public static  boolean DEBUG_ENABLED = false;
    /**
     * 检查串口连接状态
     * 检查串口连接状态 - 优化版本,添加重试机制
     * @return true-串口已连接, false-串口未连接
     */
    public static boolean checkSerialConnection() {
@@ -42,7 +55,9 @@
            boolean result = Sendmsg.isPortOpen();
            
            if (result) {
                System.out.println("串口连接正常");
                if (DEBUG_ENABLED) {
                    System.out.println("串口连接正常");
                }
                serialConnected = true;
            } else {
                System.err.println("串口连接失败 - 串口未打开");
@@ -57,7 +72,25 @@
    }
    
    /**
     * 启动轮询查询
     * 带重试的串口连接检查
     */
    private static boolean checkSerialConnectionWithRetry() {
        for (int i = 0; i < 3; i++) {
            if (checkSerialConnection()) {
                return true;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }
        return false;
    }
    /**
     * 启动轮询查询 - 优化版本
     * @return true-启动成功, false-启动失败
     */
    public static boolean startPolling() {
@@ -67,7 +100,7 @@
        }
        
        // 启动前严格检查串口连接
        if (!checkSerialConnection()) {
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法启动轮询查询");
            return false;
        }
@@ -77,23 +110,26 @@
        
        isRunning = true;
        isPaused = false;
        shouldStop.set(false);
        
        try {
            pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread");
            pollingThread.setDaemon(true);
            pollingThread.start();
            System.out.println("轮询查询已启动,间隔: " + pollingInterval + "ms");
            pollingThread.start();
            if (DEBUG_ENABLED) {
                System.out.println("轮询查询已启动,间隔: " + pollingInterval + "ms");
            }
            return true;
        } catch (Exception e) {
            System.err.println("启动轮询查询线程时发生异常: " + e.getMessage());
            isRunning = false;
            shouldStop.set(true);
            return false;
        }
    }
    
    /**
     * 停止轮询查询
     * 停止轮询查询 - 修复版本
     * @return true-停止成功, false-停止失败
     */
    public static boolean stopPolling() {
@@ -102,19 +138,31 @@
            return false;
        }
        
        shouldStop.set(true);
        isRunning = false;
        isPaused = false;
        if (pollingThread != null) {
            pollingThread.interrupt();
            try {
                pollingThread.join(1000); // 等待线程结束,最多1秒
                pollingThread.join(3000); // 等待3秒
                // 检查线程是否还在运行
                if (pollingThread.isAlive()) {
                    System.err.println("轮询线程未在3秒内停止,标记为守护线程并忽略");
                    // 不强制停止,而是确保它是守护线程
                    pollingThread.setDaemon(true);
                }
            } catch (InterruptedException e) {
                System.err.println("停止轮询查询时被中断: " + e.getMessage());
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                System.err.println("停止轮询线程时发生异常: " + e.getMessage());
            } finally {
                pollingThread = null;
            }
            pollingThread = null;
        }
        
        shouldStop.set(false);
        System.out.println("轮询查询已停止");
        return true;
    }
@@ -125,12 +173,16 @@
     */
    public static boolean pausePolling() {
        if (!isRunning) {
            System.out.println("轮询查询未在运行,无法暂停");
            if (DEBUG_ENABLED) {
                System.out.println("轮询查询未在运行,无法暂停");
            }
            return false;
        }
        
        if (isPaused) {
            System.out.println("轮询查询已经处于暂停状态");
            if (DEBUG_ENABLED) {
                System.out.println("轮询查询已经处于暂停状态");
            }
            return false;
        }
        
@@ -155,7 +207,7 @@
        }
        
        // 恢复前检查串口连接
        if (!checkSerialConnection()) {
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法恢复轮询查询");
            return false;
        }
@@ -228,7 +280,7 @@
        
        // 等待一小段时间确保线程完全停止
        try {
            Thread.sleep(100);
            Thread.sleep(200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
@@ -256,22 +308,40 @@
    }
    
    /**
     * 轮询任务内部类
     * 获取缓存的查询指令
     */
    private static String getCachedQueryCommand(int slotNumber) {
        return queryCommandCache.computeIfAbsent(slotNumber, QueryData::queryData);
    }
    /**
     * 清空查询指令缓存(当查询逻辑变化时调用)
     */
    public static void clearQueryCache() {
        queryCommandCache.clear();
        System.out.println("查询指令缓存已清空");
    }
    /**
     * 轮询任务内部类 - 优化版本
     * 优化内存使用:避免在循环中创建新对象
     * 添加批量处理和性能监控
     */
    private static class PollingTask implements Runnable {
        private int currentSlot = MIN_SLOT;
        private int currentIndex = 0; // 当前索引,用于遍历slotArray
        private int consecutiveFailures = 0; // 连续失败次数
        private static final int MAX_CONSECUTIVE_FAILURES = 5; // 最大连续失败次数
        
        @Override
        public void run() {
            System.out.println("轮询查询线程开始运行");
            
            while (isRunning && !Thread.currentThread().isInterrupted()) {
            while (isRunning && !Thread.currentThread().isInterrupted() && !shouldStop.get()) {
                try {
                    // 检查是否暂停
                    if (isPaused) {
                        synchronized (lunxun.class) {
                            while (isPaused && isRunning) {
                            while (isPaused && isRunning && !shouldStop.get()) {
                                lunxun.class.wait(1000); // 等待1秒或直到被唤醒
                            }
                        }
@@ -279,28 +349,61 @@
                    }
                    
                    // 定期检查串口连接状态(每10次循环检查一次)
                    if (currentSlot % 10 == 0 && !checkSerialConnection()) {
                    if (currentIndex % 10 == 0 && !checkSerialConnectionWithRetry()) {
                        System.err.println("串口连接断开,暂停轮询");
                        pausePolling();
                        continue;
                    }
                    
                    // 发送当前卡槽的查询指令
                    sendQueryToSlot(currentSlot);
                    // 移动到下一个卡槽
                    currentSlot++;
                    if (currentSlot > MAX_SLOT) {
                        currentSlot = MIN_SLOT; // 循环回到第一个卡槽
                        // 在循环回到第一个卡槽后,等待间隔时间
                        // 避免连续发送两个相邻周期的第一个卡槽
                    // 获取卡槽数组
                    Fkj[] slotArray = SlotManager.getSlotArray();
                    if (slotArray == null || slotArray.length == 0) {
                        System.err.println("卡槽数组未初始化");
                        Thread.sleep(pollingInterval);
                        continue; // 跳过本次循环的后续等待
                        continue;
                    }
                    
                    // 等待指定的间隔时间
                    Thread.sleep(pollingInterval);
                    // 遍历所有卡槽,只给 hasCard != 1 的卡槽发送查询指令
                    boolean sentQuery = false;
                    int checkedSlots = 0;
                    int maxSlotsPerCycle = Math.min(10, slotArray.length); // 每周期最多检查10个卡槽
                    for (int i = 0; i < maxSlotsPerCycle && checkedSlots < slotArray.length; i++) {
                        Fkj slot = slotArray[currentIndex];
                        if (slot != null) {
                            String hasCard = slot.getHasCard();
                            if (!"1".equals(hasCard)) {
                                int slotNumber = currentIndex + 1;
                                if (sendQueryToSlot(slotNumber)) {
                                    sentQuery = true;
                                    consecutiveFailures = 0;
                                    // 关键修复:在break前先更新索引
                                    currentIndex = (currentIndex + 1) % slotArray.length;
                                    checkedSlots++;
                                    Thread.sleep(pollingInterval);
                                    break;
                                } else {
                                    consecutiveFailures++;
                                    if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
                                        System.err.println("连续失败次数过多,暂停轮询");
                                        pausePolling();
                                        break;
                                    }
                                }
                            }
                        }
                        // 对于不需要发送查询的卡槽,正常更新索引
                        currentIndex = (currentIndex + 1) % slotArray.length;
                        checkedSlots++;
                    }
                    // 如果没有找到需要查询的卡槽,等待一段时间再继续
                    if (!sentQuery) {
                        Thread.sleep(pollingInterval * 2); // 没有查询时等待时间加倍
                    }
                    
                } catch (InterruptedException e) {
                    System.out.println("轮询查询线程被中断");
@@ -308,6 +411,7 @@
                    break;
                } catch (Exception e) {
                    System.err.println("轮询查询过程中发生异常: " + e.getMessage());
                    consecutiveFailures++;
                    
                    // 发生异常时等待一段时间再继续
                    try {
@@ -323,13 +427,13 @@
        }
        
        /**
         * 向指定卡槽发送查询指令
         * 优化:避免重复创建对象,使用局部变量
         * 向指定卡槽发送查询指令 - 优化版本
         * 使用缓存指令,优化调试输出
         */
        private void sendQueryToSlot(int slotNumber) {
        private boolean sendQueryToSlot(int slotNumber) {
            try {
                // 生成查询指令
                String queryCommand = QueryData.queryData(slotNumber);
                // 使用缓存的查询指令
                String queryCommand = getCachedQueryCommand(slotNumber);
                
                if (queryCommand != null && !queryCommand.trim().isEmpty()) {
                    // 发送到串口
@@ -337,22 +441,28 @@
                    
                    if (sendResult) {
                        // 只在调试时输出,避免频繁打印
                        if (slotNumber == 1 || slotNumber % 20 == 0) {
                            System.out.println("发送查询指令到卡槽 " + slotNumber);
                        if (DEBUG_ENABLED) {
                            SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)", slotNumber));
                        }
                        return true;
                    } else {
                        System.err.println("发送查询指令到卡槽 " + slotNumber + " 失败");
                        if (DEBUG_ENABLED) {
                            SystemDebugDialog.appendAsciiData("Send query command to card slot err");
                        }
                        // 发送失败可能是串口断开,更新连接状态
                        serialConnected = false;
                        return false;
                    }
                } else {
                    System.err.println("生成的查询指令为空,卡槽: " + slotNumber);
                    return false;
                }
                
            } catch (Exception e) {
                System.err.println("发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
                // 发生异常时更新串口连接状态
                serialConnected = false;
                return false;
            }
        }
    }
@@ -369,21 +479,23 @@
        }
        
        // 检查串口连接
        if (!checkSerialConnection()) {
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法发送查询指令");
            return false;
        }
        
        try {
            // 生成查询指令
            String queryCommand = QueryData.queryData(slotNumber);
            // 使用缓存的查询指令
            String queryCommand = getCachedQueryCommand(slotNumber);
            
            if (queryCommand != null && !queryCommand.trim().isEmpty()) {
                // 发送到串口
                boolean sendResult = Sendmsg.sendMessage(queryCommand);
                
                if (sendResult) {
                    System.out.println("立即查询成功 - 卡槽 " + slotNumber);
                    if (DEBUG_ENABLED) {
                        System.out.println("立即查询成功 - 卡槽 " + slotNumber);
                    }
                    return true;
                } else {
                    System.err.println("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败");
@@ -401,35 +513,48 @@
    }
    
    /**
     * 立即向所有卡槽发送查询指令(批量)
     * 立即向所有卡槽发送查询指令(批量)- 优化版本
     * @return 成功发送的指令数量
     */
    public static int sendImmediateQueryToAll() {
        // 检查串口连接
        if (!checkSerialConnection()) {
        if (!checkSerialConnectionWithRetry()) {
            System.err.println("串口未连接,无法发送批量查询指令");
            return 0;
        }
        
        int successCount = 0;
        int batchSize = 5; // 每批次发送5个查询
        int totalSlots = MAX_SLOT - MIN_SLOT + 1;
        
        System.out.println("开始批量查询所有卡槽...");
        
        for (int slot = MIN_SLOT; slot <= MAX_SLOT; slot++) {
            if (sendImmediateQuery(slot)) {
                successCount++;
        for (int batchStart = MIN_SLOT; batchStart <= MAX_SLOT; batchStart += batchSize) {
            if (shouldStop.get()) {
                break;
            }
            
            // 小间隔避免串口拥堵
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            int batchEnd = Math.min(batchStart + batchSize - 1, MAX_SLOT);
            // 批次内查询
            for (int slot = batchStart; slot <= batchEnd; slot++) {
                if (sendImmediateQuery(slot)) {
                    successCount++;
                }
            }
            // 批次间间隔,避免串口拥堵
            if (batchEnd < MAX_SLOT) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
        
        System.out.println("批量查询完成,成功发送: " + successCount + "/" + MAX_SLOT);
        System.out.println("批量查询完成,成功发送: " + successCount + "/" + totalSlots);
        return successCount;
    }
    
@@ -467,9 +592,10 @@
        }
        
        String serialStatus = serialConnected ? "已连接" : "未连接";
        int cacheSize = queryCommandCache.size();
        
        return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 卡槽范围: %d-%d",
                           status, serialStatus, pollingInterval, MIN_SLOT, MAX_SLOT);
        return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d",
                           status, serialStatus, pollingInterval, cacheSize, MIN_SLOT, MAX_SLOT);
    }
    
    /**
@@ -497,7 +623,7 @@
            // 请求恢复
            if (isPaused) {
                // 恢复前检查串口连接
                if (!checkSerialConnection()) {
                if (!checkSerialConnectionWithRetry()) {
                    System.err.println("串口未连接,无法恢复轮询查询");
                    return false;
                }
@@ -514,4 +640,20 @@
            }
        }
    }
    /**
     * 获取性能统计信息
     */
    public static String getPerformanceStats() {
        return String.format("查询指令缓存大小: %d, 轮询间隔: %dms",
                           queryCommandCache.size(), pollingInterval);
    }
   public static boolean isDEBUG_ENABLED() {
      return DEBUG_ENABLED;
   }
   public static void setDEBUG_ENABLED(boolean dEBUG_ENABLED) {
      DEBUG_ENABLED = dEBUG_ENABLED;
   }
}