张世豪
6 小时以前 d22349714c8d199c02f336f90fba841ef8f5cd39
src/chushihua/lunxun.java
@@ -1,517 +1,904 @@
package chushihua;
import chuankou.Sendmsg;
import dialog.Errlog;
import home.Fkj;
import home.MachineConfig;
import publicway.QueryData;
import xitongshezhi.SystemDebugDialog;
import java.util.Iterator;
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 Thread pollingThread;
    private static int pollingInterval = 100; // 默认轮询间隔
    // 卡槽相关常量
    private static final int MIN_SLOT = 1;
    private static final int MAX_SLOT = 60;
    // 串口连接检查相关
    private static final int SERIAL_CHECK_INTERVAL = 5000; // 5秒检查一次串口连接
    private static long lastSerialCheckTime = 0;
    private static boolean serialConnected = false;
    /**
     * 检查串口连接状态
     * @return true-串口已连接, false-串口未连接
     */
    public static boolean checkSerialConnection() {
        // 避免频繁检查,每5秒检查一次
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastSerialCheckTime < SERIAL_CHECK_INTERVAL) {
            return serialConnected;
        }
        lastSerialCheckTime = currentTime;
        try {
            // 简化检查:直接检查Sendmsg的串口状态,而不是发送测试指令
            boolean result = Sendmsg.isPortOpen();
            if (result) {
                System.out.println("串口连接正常");
                serialConnected = true;
            } else {
                System.err.println("串口连接失败 - 串口未打开");
                serialConnected = false;
            }
        } catch (Exception e) {
            System.err.println("串口连接检查异常: " + e.getMessage());
            serialConnected = false;
        }
        return serialConnected;
    }
    /**
     * 启动轮询查询
     * @return true-启动成功, false-启动失败
     */
    public static boolean startPolling() {
        if (isRunning) {
            System.out.println("轮询查询已经在运行中");
            return true;
        }
        // 启动前严格检查串口连接
        if (!checkSerialConnection()) {
            System.err.println("串口未连接,无法启动轮询查询");
            return false;
        }
        // 从配置中获取轮询间隔
        loadPollingIntervalFromConfig();
        isRunning = true;
        isPaused = false;
        try {
            pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread");
            pollingThread.setDaemon(true);
            pollingThread.start();
            System.out.println("轮询查询已启动,间隔: " + pollingInterval + "ms");
            return true;
        } catch (Exception e) {
            System.err.println("启动轮询查询线程时发生异常: " + e.getMessage());
            isRunning = false;
            return false;
        }
    }
    /**
     * 停止轮询查询
     * @return true-停止成功, false-停止失败
     */
    public static boolean stopPolling() {
        if (!isRunning) {
            System.out.println("轮询查询未在运行");
            return false;
        }
        isRunning = false;
        isPaused = false;
        if (pollingThread != null) {
            pollingThread.interrupt();
            try {
                pollingThread.join(1000); // 等待线程结束,最多1秒
            } catch (InterruptedException e) {
                System.err.println("停止轮询查询时被中断: " + e.getMessage());
                Thread.currentThread().interrupt();
            }
            pollingThread = null;
        }
        System.out.println("轮询查询已停止");
        return true;
    }
    /**
     * 暂停轮询查询
     * @return true-暂停成功, false-暂停失败
     */
    public static boolean pausePolling() {
        if (!isRunning) {
            System.out.println("轮询查询未在运行,无法暂停");
            return false;
        }
        if (isPaused) {
            System.out.println("轮询查询已经处于暂停状态");
            return false;
        }
        isPaused = true;
        System.out.println("轮询查询已暂停");
        return true;
    }
    /**
     * 恢复轮询查询
     * @return true-恢复成功, false-恢复失败
     */
    public static boolean resumePolling() {
        if (!isRunning) {
            System.out.println("轮询查询未在运行,无法恢复");
            return false;
        }
        if (!isPaused) {
            System.out.println("轮询查询未处于暂停状态");
            return false;
        }
        // 恢复前检查串口连接
        if (!checkSerialConnection()) {
            System.err.println("串口未连接,无法恢复轮询查询");
            return false;
        }
        isPaused = false;
        synchronized (lunxun.class) {
            lunxun.class.notifyAll(); // 唤醒等待的线程
        }
        System.out.println("轮询查询已恢复");
        return true;
    }
    /**
     * 检查轮询状态
     * @return true-正在运行, false-已停止
     */
    public static boolean isPolling() {
        return isRunning;
    }
    /**
     * 检查是否暂停
     * @return true-已暂停, false-未暂停
     */
    public static boolean isPaused() {
        return isPaused;
    }
    /**
     * 检查串口连接状态
     * @return true-串口已连接, false-串口未连接
     */
    public static boolean isSerialConnected() {
        return serialConnected;
    }
    /**
     * 设置轮询间隔
     * @param interval 轮询间隔(毫秒)
     */
    public static void setPollingInterval(int interval) {
        if (interval < 10) {
            System.err.println("轮询间隔不能小于10ms");
            return;
        }
        pollingInterval = interval;
        System.out.println("轮询间隔已设置为: " + interval + "ms");
        // 如果正在运行,重新启动以应用新的间隔
        if (isRunning) {
            restartPolling();
        }
    }
    /**
     * 获取当前轮询间隔
     * @return 轮询间隔(毫秒)
     */
    public static int getPollingInterval() {
        return pollingInterval;
    }
    /**
     * 重新启动轮询查询
     * @return true-重启成功, false-重启失败
     */
    public static boolean restartPolling() {
        stopPolling();
        // 等待一小段时间确保线程完全停止
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return startPolling();
    }
    /**
     * 从配置中加载轮询间隔
     */
    private static void loadPollingIntervalFromConfig() {
        try {
            Chushihua configSystem = Chushihua.getInstance();
            if (configSystem.isInitialized()) {
                MachineConfig machineConfig = configSystem.getMachineConfig();
                pollingInterval = machineConfig.getPollingInterval();
                System.out.println("从配置加载轮询间隔: " + pollingInterval + "ms");
            } else {
                System.out.println("配置系统未初始化,使用默认轮询间隔: " + pollingInterval + "ms");
            }
        } catch (Exception e) {
            System.err.println("加载轮询间隔配置失败: " + e.getMessage());
            System.out.println("使用默认轮询间隔: " + pollingInterval + "ms");
        }
    }
    /**
     * 轮询任务内部类
     * 优化内存使用:避免在循环中创建新对象
     */
    private static class PollingTask implements Runnable {
        private int currentSlot = MIN_SLOT;
        @Override
        public void run() {
            System.out.println("轮询查询线程开始运行");
            while (isRunning && !Thread.currentThread().isInterrupted()) {
                try {
                    // 检查是否暂停
                    if (isPaused) {
                        synchronized (lunxun.class) {
                            while (isPaused && isRunning) {
                                lunxun.class.wait(1000); // 等待1秒或直到被唤醒
                            }
                        }
                        continue;
                    }
                    // 定期检查串口连接状态(每10次循环检查一次)
                    if (currentSlot % 10 == 0 && !checkSerialConnection()) {
                        System.err.println("串口连接断开,暂停轮询");
                        pausePolling();
                        continue;
                    }
                    // 发送当前卡槽的查询指令
                    sendQueryToSlot(currentSlot);
                    // 移动到下一个卡槽
                    currentSlot++;
                    if (currentSlot > MAX_SLOT) {
                        currentSlot = MIN_SLOT; // 循环回到第一个卡槽
                        // 在循环回到第一个卡槽后,等待间隔时间
                        // 避免连续发送两个相邻周期的第一个卡槽
                        Thread.sleep(pollingInterval);
                        continue; // 跳过本次循环的后续等待
                    }
                    // 等待指定的间隔时间
                    Thread.sleep(pollingInterval);
                } catch (InterruptedException e) {
                    System.out.println("轮询查询线程被中断");
                    Thread.currentThread().interrupt();
                    break;
                } catch (Exception e) {
                    System.err.println("轮询查询过程中发生异常: " + e.getMessage());
                    // 发生异常时等待一段时间再继续
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
            System.out.println("轮询查询线程结束运行");
        }
        /**
         * 向指定卡槽发送查询指令
         * 优化:避免重复创建对象,使用局部变量
         */
        private void sendQueryToSlot(int slotNumber) {
            try {
                // 生成查询指令
                String queryCommand = QueryData.queryData(slotNumber);
                if (queryCommand != null && !queryCommand.trim().isEmpty()) {
                    // 发送到串口
                    boolean sendResult = Sendmsg.sendMessage(queryCommand);
                    if (sendResult) {
                        // 只在调试时输出,避免频繁打印
                        if (slotNumber == 1 || slotNumber % 20 == 0) {
                            System.out.println("发送查询指令到卡槽 " + slotNumber);
                        }
                    } else {
                        System.err.println("发送查询指令到卡槽 " + slotNumber + " 失败");
                        // 发送失败可能是串口断开,更新连接状态
                        serialConnected = false;
                    }
                } else {
                    System.err.println("生成的查询指令为空,卡槽: " + slotNumber);
                }
            } catch (Exception e) {
                System.err.println("发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
                // 发生异常时更新串口连接状态
                serialConnected = false;
            }
        }
    }
    /**
     * 立即向指定卡槽发送查询指令(不等待轮询)
     * @param slotNumber 卡槽编号 (1-60)
     * @return true-发送成功, false-发送失败
     */
    public static boolean sendImmediateQuery(int slotNumber) {
        if (slotNumber < MIN_SLOT || slotNumber > MAX_SLOT) {
            System.err.println("卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间");
            return false;
        }
        // 检查串口连接
        if (!checkSerialConnection()) {
            System.err.println("串口未连接,无法发送查询指令");
            return false;
        }
        try {
            // 生成查询指令
            String queryCommand = QueryData.queryData(slotNumber);
            if (queryCommand != null && !queryCommand.trim().isEmpty()) {
                // 发送到串口
                boolean sendResult = Sendmsg.sendMessage(queryCommand);
                if (sendResult) {
                    System.out.println("立即查询成功 - 卡槽 " + slotNumber);
                    return true;
                } else {
                    System.err.println("立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败");
                    return false;
                }
            } else {
                System.err.println("立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber);
                return false;
            }
        } catch (Exception e) {
            System.err.println("立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
            return false;
        }
    }
    /**
     * 立即向所有卡槽发送查询指令(批量)
     * @return 成功发送的指令数量
     */
    public static int sendImmediateQueryToAll() {
        // 检查串口连接
        if (!checkSerialConnection()) {
            System.err.println("串口未连接,无法发送批量查询指令");
            return 0;
        }
        int successCount = 0;
        System.out.println("开始批量查询所有卡槽...");
        for (int slot = MIN_SLOT; slot <= MAX_SLOT; slot++) {
            if (sendImmediateQuery(slot)) {
                successCount++;
            }
            // 小间隔避免串口拥堵
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        System.out.println("批量查询完成,成功发送: " + successCount + "/" + MAX_SLOT);
        return successCount;
    }
    /**
     * 手动设置串口连接状态(用于外部检测到串口状态变化时调用)
     * @param connected 串口连接状态
     */
    public static void setSerialConnected(boolean connected) {
        serialConnected = connected;
        lastSerialCheckTime = System.currentTimeMillis();
        if (connected) {
            System.out.println("串口连接状态已设置为: 已连接");
        } else {
            System.err.println("串口连接状态已设置为: 未连接");
            // 如果串口断开且轮询正在运行,自动暂停轮询
            if (isRunning && !isPaused) {
                pausePolling();
            }
        }
    }
    /**
     * 获取轮询状态信息
     * @return 状态信息字符串
     */
    public static String getPollingStatus() {
        String status;
        if (!isRunning) {
            status = "已停止";
        } else if (isPaused) {
            status = "已暂停";
        } else {
            status = "运行中";
        }
        String serialStatus = serialConnected ? "已连接" : "未连接";
        return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 卡槽范围: %d-%d",
                           status, serialStatus, pollingInterval, MIN_SLOT, MAX_SLOT);
    }
    /**
     * 直接设置轮询暂停状态(供其他类调用)
     * @param paused true-暂停轮询, false-恢复轮询
     * @return true-设置成功, false-设置失败(如轮询未运行)
     */
    public static boolean setPollingPaused(boolean paused) {
        if (!isRunning) {
            System.out.println("轮询查询未在运行,无法设置暂停状态");
            return false;
        }
        if (paused) {
            // 请求暂停
            if (!isPaused) {
                isPaused = true;
                System.out.println("轮询查询已通过外部调用暂停");
                return true;
            } else {
                System.out.println("轮询查询已经处于暂停状态");
                return false;
            }
        } else {
            // 请求恢复
            if (isPaused) {
                // 恢复前检查串口连接
                if (!checkSerialConnection()) {
                    System.err.println("串口未连接,无法恢复轮询查询");
                    return false;
                }
                isPaused = false;
                synchronized (lunxun.class) {
                    lunxun.class.notifyAll(); // 唤醒等待的线程
                }
                System.out.println("轮询查询已通过外部调用恢复");
                return true;
            } else {
                System.out.println("轮询查询未处于暂停状态");
                return false;
            }
        }
    }
   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; // 默认轮询间隔
   public static boolean sendChaxunzhiling=true;//是否向串口发送查询指令
   // 卡槽相关常量
   private static final int MIN_SLOT = 1;
   private static final int MAX_SLOT = 60;
   // 串口连接检查相关
   private static final int SERIAL_CHECK_INTERVAL = 5000; // 5秒检查一次串口连接
   private static long lastSerialCheckTime = 0;
   private static boolean serialConnected = false;
   // 性能优化:查询指令缓存
   private static final Map<Integer, String> queryCommandCache = new ConcurrentHashMap<>();
   // 内存优化:缓存大小限制和清理机制
   private static final int MAX_CACHE_SIZE = 100;
   private static final long CACHE_CLEANUP_INTERVAL = 60000; // 1分钟清理一次
   private static long lastCleanupTime = 0;
   // 错误日志限流机制
   private static final Map<String, Long> lastErrorLogTime = new ConcurrentHashMap<>();
   private static final long ERROR_LOG_INTERVAL = 5000; // 相同错误5秒内只记录一次
   // 调试模式控制
   public static  boolean DEBUG_ENABLED = false;
   // 新增:不同状态卡槽的查询频率控制
   private static final int NO_CARD_QUERY_INTERVAL = 100;    // 无卡卡槽查询间隔:100ms
   private static final int HAS_CARD_QUERY_INTERVAL = 10000; // 有卡卡槽查询间隔:10秒
   private static final Map<Integer, Long> lastQueryTimeMap = new ConcurrentHashMap<>(); // 记录每个卡槽的最后查询时间
   public static boolean isSendChaxunzhiling() {
      return sendChaxunzhiling;
   }
   public static void setSendChaxunzhiling(boolean sendChaxunzhiling) {
      lunxun.sendChaxunzhiling = sendChaxunzhiling;
   }
   /**
    * 检查串口连接状态 - 优化版本,添加重试机制
    * @return true-串口已连接, false-串口未连接
    */
   public static boolean checkSerialConnection() {
      // 避免频繁检查,每5秒检查一次
      long currentTime = System.currentTimeMillis();
      if (currentTime - lastSerialCheckTime < SERIAL_CHECK_INTERVAL) {
         return serialConnected;
      }
      lastSerialCheckTime = currentTime;
      try {
         // 简化检查:直接检查Sendmsg的串口状态,而不是发送测试指令
         boolean result = Sendmsg.isPortOpen();
         if (result) {
            if (DEBUG_ENABLED) {
               //System.out.println("串口连接正常");
            }
            serialConnected = true;
         } else {
            logErrorWithRateLimit("serial_connection_failed", "串口连接失败 - 串口未打开");
            serialConnected = false;
         }
      } catch (Exception e) {
         logErrorWithRateLimit("serial_connection_exception", "串口连接检查异常: " + e.getMessage());
         serialConnected = false;
      }
      return serialConnected;
   }
   /**
    * 带重试的串口连接检查
    */
   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() {
      if (isRunning) {
         //System.out.println("轮询查询已经在运行中");
         return true;
      }
      // 启动前严格检查串口连接
      if (!checkSerialConnectionWithRetry()) {
         logErrorWithRateLimit("start_polling_serial_failed", "串口未连接,无法启动轮询查询");
         return false;
      }
      // 启动前先清理一次内存
      performCleanup();
      // 从配置中获取轮询间隔
      loadPollingIntervalFromConfig();
      // 初始化最后查询时间记录
      initializeLastQueryTimes();
      isRunning = true;
      isPaused = false;
      shouldStop.set(false);
      try {
         pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread");
         pollingThread.setDaemon(true);
         pollingThread.start();
         return true;
      } catch (Exception e) {
         logErrorWithRateLimit("start_polling_thread_exception", "启动轮询查询线程时发生异常: " + e.getMessage());
         isRunning = false;
         shouldStop.set(true);
         return false;
      }
   }
   /**
    * 初始化最后查询时间记录
    */
   private static void initializeLastQueryTimes() {
      lastQueryTimeMap.clear();
      for (int i = MIN_SLOT; i <= MAX_SLOT; i++) {
         lastQueryTimeMap.put(i, 0L); // 初始化为0,表示从未查询过
      }
   }
   /**
    * 停止轮询查询 - 修复版本
    * @return true-停止成功, false-停止失败
    */
   public static boolean stopPolling() {
      if (!isRunning) {
         //System.out.println("轮询查询未在运行");
         return false;
      }
      shouldStop.set(true);
      isRunning = false;
      isPaused = false;
      if (pollingThread != null) {
         pollingThread.interrupt();
         try {
            pollingThread.join(3000); // 等待3秒
            // 检查线程是否还在运行
            if (pollingThread.isAlive()) {
               logErrorWithRateLimit("polling_thread_stop_timeout", "轮询线程未在3秒内停止,标记为守护线程并忽略");
               // 不强制停止,而是确保它是守护线程
               pollingThread.setDaemon(true);
            }
         } catch (InterruptedException e) {
            logErrorWithRateLimit("stop_polling_interrupted", "停止轮询查询时被中断: " + e.getMessage());
            Thread.currentThread().interrupt();
         } catch (Exception e) {
            logErrorWithRateLimit("stop_polling_exception", "停止轮询线程时发生异常: " + e.getMessage());
         } finally {
            pollingThread = null;
         }
      }
      shouldStop.set(false);
      //System.out.println("轮询查询已停止 - 串口数据接收不受影响");
      return true;
   }
   /**
    * 暂停轮询查询
    * @return true-暂停成功, false-暂停失败
    */
   public static boolean pausePolling() {
      if (!isRunning) {
         if (DEBUG_ENABLED) {
            //System.out.println("轮询查询未在运行,无法暂停");
         }
         return false;
      }
      if (isPaused) {
         if (DEBUG_ENABLED) {
            //System.out.println("轮询查询已经处于暂停状态");
         }
         return false;
      }
      isPaused = true;
      //System.out.println("轮询查询已暂停 - 仅停止发送查询指令");
      return true;
   }
   /**
    * 恢复轮询查询
    * @return true-恢复成功, false-恢复失败
    */
   public static boolean resumePolling() {
      if (!isRunning) {
         //System.out.println("轮询查询未在运行,无法恢复");
         return false;
      }
      if (!isPaused) {
         //System.out.println("轮询查询未处于暂停状态");
         return false;
      }
      // 恢复前检查串口连接
      if (!checkSerialConnectionWithRetry()) {
         logErrorWithRateLimit("resume_polling_serial_failed", "串口未连接,无法恢复轮询查询");
         return false;
      }
      isPaused = false;
      synchronized (lunxun.class) {
         lunxun.class.notifyAll(); // 唤醒等待的线程
      }
      //System.out.println("轮询查询已恢复");
      return true;
   }
   /**
    * 检查轮询状态
    * @return true-正在运行, false-已停止
    */
   public static boolean isPolling() {
      return isRunning;
   }
   /**
    * 检查是否暂停
    * @return true-已暂停, false-未暂停
    */
   public static boolean isPaused() {
      return isPaused;
   }
   /**
    * 检查串口连接状态
    * @return true-串口已连接, false-串口未连接
    */
   public static boolean isSerialConnected() {
      return serialConnected;
   }
   /**
    * 设置轮询间隔
    * @param interval 轮询间隔(毫秒)
    */
   public static void setPollingInterval(int interval) {
      if (interval < 10) {
         logErrorWithRateLimit("polling_interval_too_small", "轮询间隔不能小于10ms");
         return;
      }
      pollingInterval = interval;
      //System.out.println("轮询间隔已设置为: " + interval + "ms");
      // 如果正在运行,重新启动以应用新的间隔
      if (isRunning) {
         restartPolling();
      }
   }
   /**
    * 获取当前轮询间隔
    * @return 轮询间隔(毫秒)
    */
   public static int getPollingInterval() {
      return pollingInterval;
   }
   /**
    * 重新启动轮询查询
    * @return true-重启成功, false-重启失败
    */
   public static boolean restartPolling() {
      stopPolling();
      // 等待一小段时间确保线程完全停止
      try {
         Thread.sleep(200);
      } catch (InterruptedException e) {
         Thread.currentThread().interrupt();
      }
      return startPolling();
   }
   /**
    * 从配置中加载轮询间隔
    */
   private static void loadPollingIntervalFromConfig() {
      try {
         Chushihua configSystem = Chushihua.getInstance();
         if (configSystem.isInitialized()) {
            MachineConfig machineConfig = configSystem.getMachineConfig();
            pollingInterval = machineConfig.getPollingInterval();
            //System.out.println("从配置加载轮询间隔: " + pollingInterval + "ms");
         } else {
            //System.out.println("配置系统未初始化,使用默认轮询间隔: " + pollingInterval + "ms");
         }
      } catch (Exception e) {
         logErrorWithRateLimit("load_polling_interval_failed", "加载轮询间隔配置失败: " + e.getMessage());
         //System.out.println("使用默认轮询间隔: " + pollingInterval + "ms");
      }
   }
   /**
    * 获取缓存的查询指令
    */
   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 currentIndex = 0; // 当前索引,用于遍历slotArray
      private int consecutiveFailures = 0; // 连续失败次数
      private static final int MAX_CONSECUTIVE_FAILURES = 5; // 最大连续失败次数
      private final StringBuilder debugBuilder = new StringBuilder(100); // 重用 StringBuilder
      @Override
      public void run() {
         //System.out.println("轮询查询线程开始运行");
         while (isRunning && !Thread.currentThread().isInterrupted() && !shouldStop.get()) {
            try {
//               System.out.println("查询中.....线程");
               // 检查是否暂停
               if (isPaused) {
                  synchronized (lunxun.class) {
                     while (isPaused && isRunning && !shouldStop.get()) {
                        lunxun.class.wait(1000); // 等待1秒或直到被唤醒
                     }
                  }
                  continue;
               }
               // 定期检查串口连接状态(每10次循环检查一次)
               if (currentIndex % 10 == 0 && !checkSerialConnectionWithRetry()) {
                  logErrorWithRateLimit("serial_disconnected", "串口连接断开,暂停轮询");
                  pausePolling();
                  continue;
               }
               // 定期清理缓存(每100次循环清理一次)
               if (currentIndex % 100 == 0) {
                  cleanupOldCache();
               }
               // 获取卡槽数组
               Fkj[] slotArray = SlotManager.getSlotArray();
               if (slotArray == null || slotArray.length == 0) {
                  logErrorWithRateLimit("slot_array_not_initialized", "卡槽数组未初始化");
                  Thread.sleep(pollingInterval);
                  continue;
               }
               // 新增:根据卡槽状态和查询频率决定是否发送查询
               boolean sentQuery = false;
               long currentTime = System.currentTimeMillis();
               // 遍历卡槽,寻找需要查询的卡槽
               for (int i = 0; i < slotArray.length && !sentQuery; i++) {
                  int slotIndex = (currentIndex + i) % slotArray.length;
                  Fkj slot = slotArray[slotIndex];
                  if (slot != null) {
                     String hasCard = slot.getHasCard();
                     int slotNumber = slotIndex + 1;
                     Long lastQueryTime = lastQueryTimeMap.get(slotNumber);
                     // 确定查询间隔:只有hasCard="1"的卡槽使用10秒间隔,其他情况(包括"-1")都使用100ms间隔
                     int queryInterval = "1".equals(hasCard) ? HAS_CARD_QUERY_INTERVAL : NO_CARD_QUERY_INTERVAL;
                     // 检查是否达到查询时间
                     if (lastQueryTime == null || currentTime - lastQueryTime >= queryInterval) {
                        if (sendQueryToSlot(slotNumber)) {
                           // 更新最后查询时间
                           lastQueryTimeMap.put(slotNumber, currentTime);
                           sentQuery = true;
                           consecutiveFailures = 0;
                           // 成功发送查询后,等待100ms再继续下一个查询
                           Thread.sleep(100);
                           if (DEBUG_ENABLED) {
                              String status;
                              if ("1".equals(hasCard)) {
                                 status = "有卡";
                              } else if ("-1".equals(hasCard)) {
                                 status = "未知";
                              } else {
                                 status = "无卡";
                              }
                              // 使用重用的 StringBuilder 构建调试信息
                              debugBuilder.setLength(0);
                              debugBuilder.append("Slot ").append(slotNumber)
                                         .append(" (").append(status).append(") 查询成功,间隔: ")
                                         .append(queryInterval).append("ms\n");
                              SystemDebugDialog.appendAsciiData(debugBuilder.toString());
                           }
                        } else {
                           consecutiveFailures++;
                           if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
                              logErrorWithRateLimit("consecutive_failures", "lunxun连续失败次数过多,暂停轮询");
                              pausePolling();
                              break;
                           }
                        }
                     }
                  }
               }
               // 更新当前索引
               currentIndex = (currentIndex + 1) % slotArray.length;
               // 如果没有发送查询,等待一段时间再继续
               if (!sentQuery) {
                  Thread.sleep(pollingInterval);
               }
            } catch (InterruptedException e) {
               //System.out.println("轮询查询线程被中断");
               Thread.currentThread().interrupt();
               break;
            } catch (Exception e) {
               logErrorWithRateLimit("polling_exception", "轮询查询过程中发生异常: " + e.getMessage());
               consecutiveFailures++;
               // 发生异常时等待一段时间再继续
               try {
                  Thread.sleep(1000);
               } catch (InterruptedException ie) {
                  Thread.currentThread().interrupt();
                  break;
               }
            }
         }
         //System.out.println("轮询查询线程结束运行");
      }
      /**
       * 向指定卡槽发送查询指令 - 优化版本
       * 使用缓存指令,优化调试输出
       */
      private boolean sendQueryToSlot(int slotNumber) {
         try {
            // 使用缓存的查询指令
            String queryCommand = getCachedQueryCommand(slotNumber);
//             System.out.println("指令是:"+queryCommand);
            if (DEBUG_ENABLED) {
               SystemDebugDialog.appendAsciiData("send to "+slotNumber+" queryCommand");
            }
            if (queryCommand != null && !queryCommand.trim().isEmpty()) {
               // 发送到串口
               if(sendChaxunzhiling) {
                  boolean sendResult = Sendmsg.sendMessage(queryCommand);
                  if (sendResult) {
                     return true;
                  } else {
                     if (DEBUG_ENABLED) {
                        SystemDebugDialog.appendAsciiData(slotNumber+" Send query command to card slot err");
                     }
                     // 发送失败可能是串口断开,更新连接状态
                     serialConnected = false;
                     return false;
                  }
               }else {
                  return false;
               }
            } else {
               logErrorWithRateLimit("empty_query_command", "生成的查询指令为空,卡槽: " + slotNumber);
               return false;
            }
         } catch (Exception e) {
            logErrorWithRateLimit("send_query_exception", "发送查询指令到卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
            // 发生异常时更新串口连接状态
            serialConnected = false;
            return false;
         }
      }
   }
   /**
    * 立即向指定卡槽发送查询指令(不等待轮询)
    * @param slotNumber 卡槽编号 (1-60)
    * @return true-发送成功, false-发送失败
    */
   public static boolean sendImmediateQuery(int slotNumber) {
      if (slotNumber < MIN_SLOT || slotNumber > MAX_SLOT) {
         logErrorWithRateLimit("invalid_slot_number", "卡槽编号必须在" + MIN_SLOT + "-" + MAX_SLOT + "之间");
         return false;
      }
      // 检查串口连接
      if (!checkSerialConnectionWithRetry()) {
         logErrorWithRateLimit("immediate_query_serial_failed", "串口未连接,无法发送查询指令");
         return false;
      }
      try {
         // 使用缓存的查询指令
         String queryCommand = getCachedQueryCommand(slotNumber);
         if (queryCommand != null && !queryCommand.trim().isEmpty()) {
            // 发送到串口
            boolean sendResult = Sendmsg.sendMessage(queryCommand);
            if (sendResult) {
               // 更新最后查询时间
               lastQueryTimeMap.put(slotNumber, System.currentTimeMillis());
               if (DEBUG_ENABLED) {
                  //System.out.println("立即查询成功 - 卡槽 " + slotNumber);
               }
               return true;
            } else {
               logErrorWithRateLimit("immediate_query_send_failed", "立即查询失败 - 发送指令到卡槽 " + slotNumber + " 失败");
               return false;
            }
         } else {
            logErrorWithRateLimit("immediate_query_empty_command", "立即查询失败 - 生成的查询指令为空,卡槽: " + slotNumber);
            return false;
         }
      } catch (Exception e) {
         logErrorWithRateLimit("immediate_query_exception", "立即查询卡槽 " + slotNumber + " 时发生异常: " + e.getMessage());
         return false;
      }
   }
   /**
    * 立即向所有卡槽发送查询指令(批量)- 优化版本
    * @return 成功发送的指令数量
    */
   public static int sendImmediateQueryToAll() {
      // 检查串口连接
      if (!checkSerialConnectionWithRetry()) {
         logErrorWithRateLimit("batch_query_serial_failed", "串口未连接,无法发送批量查询指令");
         return 0;
      }
      int successCount = 0;
      int batchSize = 5; // 每批次发送5个查询
      int totalSlots = MAX_SLOT - MIN_SLOT + 1;
      long currentTime = System.currentTimeMillis();
      //System.out.println("开始批量查询所有卡槽...");
      for (int batchStart = MIN_SLOT; batchStart <= MAX_SLOT; batchStart += batchSize) {
         if (shouldStop.get()) {
            break;
         }
         int batchEnd = Math.min(batchStart + batchSize - 1, MAX_SLOT);
         // 批次内查询
         for (int slot = batchStart; slot <= batchEnd; slot++) {
            if (sendImmediateQuery(slot)) {
               successCount++;
               // 更新最后查询时间
               lastQueryTimeMap.put(slot, currentTime);
            }
         }
         // 批次间间隔,避免串口拥堵
         if (batchEnd < MAX_SLOT) {
            try {
               Thread.sleep(50);
            } catch (InterruptedException e) {
               Thread.currentThread().interrupt();
               break;
            }
         }
      }
      //System.out.println("批量查询完成,成功发送: " + successCount + "/" + totalSlots);
      return successCount;
   }
   /**
    * 手动设置串口连接状态(用于外部检测到串口状态变化时调用)
    * @param connected 串口连接状态
    */
   public static void setSerialConnected(boolean connected) {
      serialConnected = connected;
      lastSerialCheckTime = System.currentTimeMillis();
      if (connected) {
         //            //System.out.println("串口连接状态已设置为: 已连接");
      } else {
         logErrorWithRateLimit("serial_disconnected_external", "串口连接状态已设置为: 未连接");
         // 如果串口断开且轮询正在运行,自动暂停轮询
         if (isRunning && !isPaused) {
            pausePolling();
         }
      }
   }
   /**
    * 获取轮询状态信息
    * @return 状态信息字符串
    */
   public static String getPollingStatus() {
      String status;
      if (!isRunning) {
         status = "已停止";
      } else if (isPaused) {
         status = "已暂停";
      } else {
         status = "运行中";
      }
      String serialStatus = serialConnected ? "已连接" : "未连接";
      int cacheSize = queryCommandCache.size();
      // 统计不同状态的卡槽数量
      int noCardCount = 0;
      int hasCardCount = 0;
      Fkj[] slotArray = SlotManager.getSlotArray();
      if (slotArray != null) {
         for (Fkj slot : slotArray) {
            if (slot != null && "1".equals(slot.getHasCard())) {
               hasCardCount++;
            } else {
               noCardCount++;
            }
         }
      }
      return String.format("轮询状态: %s, 串口: %s, 间隔: %dms, 指令缓存: %d, 卡槽范围: %d-%d, 无卡: %d(100ms), 有卡: %d(10s)\n%s",
            status, serialStatus, pollingInterval, cacheSize, MIN_SLOT, MAX_SLOT,
            noCardCount, hasCardCount, getMemoryStatus());
   }
   /**
    * 直接设置轮询暂停状态(供其他类调用)
    * @param paused true-暂停轮询, false-恢复轮询
    * @return true-设置成功, false-设置失败(如轮询未运行)
    */
   public static boolean setPollingPaused(boolean paused) {
      if (!isRunning) {
         //System.out.println("轮询查询未在运行,无法设置暂停状态");
         return false;
      }
      if (paused) {
         // 请求暂停
         if (!isPaused) {
            isPaused = true;
            //System.out.println("轮询查询已通过外部调用暂停");
            return true;
         } else {
            //System.out.println("轮询查询已经处于暂停状态");
            return false;
         }
      } else {
         // 请求恢复
         if (isPaused) {
            // 恢复前检查串口连接
            if (!checkSerialConnectionWithRetry()) {
               logErrorWithRateLimit("external_resume_serial_failed", "串口未连接,无法恢复轮询查询");
               return false;
            }
            isPaused = false;
            synchronized (lunxun.class) {
               lunxun.class.notifyAll(); // 唤醒等待的线程
            }
            //System.out.println("轮询查询已通过外部调用恢复");
            return true;
         } else {
            //System.out.println("轮询查询未处于暂停状态");
            return false;
         }
      }
   }
   /**
    * 获取性能统计信息
    */
   public static String getPerformanceStats() {
      long currentTime = System.currentTimeMillis();
      int overdueNoCard = 0;
      int overdueHasCard = 0;
      Fkj[] slotArray = SlotManager.getSlotArray();
      if (slotArray != null) {
         for (int i = 0; i < slotArray.length; i++) {
            Fkj slot = slotArray[i];
            if (slot != null) {
               int slotNumber = i + 1;
               Long lastQueryTime = lastQueryTimeMap.get(slotNumber);
               if (lastQueryTime != null) {
                  String hasCard = slot.getHasCard();
                  int queryInterval = "1".equals(hasCard) ? HAS_CARD_QUERY_INTERVAL : NO_CARD_QUERY_INTERVAL;
                  if (currentTime - lastQueryTime > queryInterval) {
                     if ("1".equals(hasCard)) {
                        overdueHasCard++;
                     } else {
                        overdueNoCard++;
                     }
                  }
               }
            }
         }
      }
      return String.format("查询指令缓存大小: %d, 轮询间隔: %dms, 超时无卡: %d, 超时有卡: %d",
            queryCommandCache.size(), pollingInterval, overdueNoCard, overdueHasCard);
   }
   /**
    * 设置无卡卡槽查询间隔
    * @param interval 查询间隔(毫秒)
    */
   public static void setNoCardQueryInterval(int interval) {
      if (interval < 10) {
         logErrorWithRateLimit("no_card_interval_too_small", "无卡卡槽查询间隔不能小于10ms");
         return;
      }
      // 注意:这里只是设置常量,实际运行时需要重新启动轮询才能生效
      //System.out.println("无卡卡槽查询间隔已设置为: " + interval + "ms");
   }
   /**
    * 设置有卡卡槽查询间隔
    * @param interval 查询间隔(毫秒)
    */
   public static void setHasCardQueryInterval(int interval) {
      if (interval < 1000) {
         logErrorWithRateLimit("has_card_interval_too_small", "有卡卡槽查询间隔不能小于1000ms");
         return;
      }
      // 注意:这里只是设置常量,实际运行时需要重新启动轮询才能生效
      //System.out.println("有卡卡槽查询间隔已设置为: " + interval + "ms");
   }
   public static boolean isDEBUG_ENABLED() {
      return DEBUG_ENABLED;
   }
   public static void setDEBUG_ENABLED(boolean dEBUG_ENABLED) {
      DEBUG_ENABLED = dEBUG_ENABLED;
   }
   // ==================== 新增内存优化方法 ====================
   /**
    * 清理旧缓存 - 防止内存无限增长
    */
   private static void cleanupOldCache() {
      long currentTime = System.currentTimeMillis();
      if (currentTime - lastCleanupTime < CACHE_CLEANUP_INTERVAL) {
         return;
      }
      lastCleanupTime = currentTime;
      // 清理长时间未使用的查询时间记录
      long cleanupThreshold = currentTime - 300000; // 5分钟未使用
      lastQueryTimeMap.entrySet().removeIf(entry ->
         currentTime - entry.getValue() > cleanupThreshold
      );
      // 限制查询指令缓存大小
      if (queryCommandCache.size() > MAX_CACHE_SIZE) {
         Iterator<Map.Entry<Integer, String>> iterator = queryCommandCache.entrySet().iterator();
         int itemsToRemove = queryCommandCache.size() - MAX_CACHE_SIZE;
         for (int i = 0; i < itemsToRemove && iterator.hasNext(); i++) {
            iterator.next();
            iterator.remove();
         }
      }
      // 清理错误日志限流记录
      lastErrorLogTime.entrySet().removeIf(entry ->
         currentTime - entry.getValue() > 300000 // 5分钟
      );
   }
   /**
    * 限流错误日志 - 防止大量重复日志占用内存
    */
   private static void logErrorWithRateLimit(String errorKey, String message) {
      long currentTime = System.currentTimeMillis();
      Long lastTime = lastErrorLogTime.get(errorKey);
      if (lastTime == null || currentTime - lastTime > ERROR_LOG_INTERVAL) {
         Errlog.logOperation(message);
         lastErrorLogTime.put(errorKey, currentTime);
         // 清理过期的错误记录
         if (lastErrorLogTime.size() > 50) {
            lastErrorLogTime.entrySet().removeIf(entry ->
               currentTime - entry.getValue() > 300000 // 5分钟
            );
         }
      }
   }
   /**
    * 获取内存状态信息
    */
   public static String getMemoryStatus() {
      Runtime runtime = Runtime.getRuntime();
      long totalMemory = runtime.totalMemory();
      long freeMemory = runtime.freeMemory();
      long usedMemory = totalMemory - freeMemory;
      long maxMemory = runtime.maxMemory();
      return String.format("内存使用: %.2fMB/%.2fMB (最大: %.2fMB), 缓存: 时间记录=%d, 指令缓存=%d, 错误记录=%d",
         usedMemory / (1024.0 * 1024.0),
         totalMemory / (1024.0 * 1024.0),
         maxMemory / (1024.0 * 1024.0),
         lastQueryTimeMap.size(),
         queryCommandCache.size(),
         lastErrorLogTime.size());
   }
   /**
    * 手动触发内存清理
    */
   public static void performCleanup() {
      // 清理查询时间记录中长时间未查询的卡槽
      long cleanupThreshold = System.currentTimeMillis() - 3600000; // 1小时
      lastQueryTimeMap.entrySet().removeIf(entry ->
         entry.getValue() < cleanupThreshold
      );
      // 清空查询指令缓存
      queryCommandCache.clear();
      // 清空错误日志限流记录
      lastErrorLogTime.clear();
      // 建议系统进行垃圾回收(但不强制)
      System.gc();
      if (DEBUG_ENABLED) {
         SystemDebugDialog.appendAsciiData("执行内存清理完成\n");
      }
   }
}