张世豪
4 小时以前 d22349714c8d199c02f336f90fba841ef8f5cd39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
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 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");
        }
    }
}