Administrator
5 days ago e2dd80eec7df85a422d11338ca9dfdb869782a79
fix(grid): 修复网格元素索引并发访问问题

- 添加 INDEX_LOCK 静态对象用于同步控制
- 修改 getLongTakeProfitCount 和 getShortTakeProfitCount 方法增加同步块
- 将 refreshIndices 方法整体包装在同步块中确保原子性
- 移动 logAll 调用到锁外避免阻塞计数查询
- 防止 clear→rebuild 窗口期读取到 0 的竞态条件问题
1 files modified
18 ■■■■ changed files
src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java 18 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
@@ -92,6 +92,9 @@
    /** 空仓止损订单 ID */
    private String shortStopLossOrderId;
    /** 索引重建锁,保证 refreshIndices() 与计数读取之间互斥,避免 clear→rebuild 窗口期读到 0 */
    private static final Object INDEX_LOCK = new Object();
    /** 全局 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
    private static final Map<Integer, GridElement> INDEX = new ConcurrentHashMap<>();
    /** 全局价格索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
@@ -169,11 +172,15 @@
        return SHORT_TP_ORDER_ID_INDEX.get(orderId);
    }
    /** @return 当前多仓止盈单数量 */
    public static int getLongTakeProfitCount() { return LONG_TP_ORDER_ID_INDEX.size(); }
    /** @return 当前多仓止盈单数量(与 refreshIndices 互斥,避免清空窗口读到 0) */
    public static int getLongTakeProfitCount() {
        synchronized (INDEX_LOCK) { return LONG_TP_ORDER_ID_INDEX.size(); }
    }
    /** @return 当前空仓止盈单数量 */
    public static int getShortTakeProfitCount() { return SHORT_TP_ORDER_ID_INDEX.size(); }
    /** @return 当前空仓止盈单数量(与 refreshIndices 互斥,避免清空窗口读到 0) */
    public static int getShortTakeProfitCount() {
        synchronized (INDEX_LOCK) { return SHORT_TP_ORDER_ID_INDEX.size(); }
    }
    /**
     * 根据多仓止损订单 ID 快速查找网格元素(O(1))。
@@ -216,6 +223,7 @@
     * 使快速查找方法获取到最新数据。
     */
    public static void refreshIndices() {
        synchronized (INDEX_LOCK) {
        PRICE_INDEX.clear();
        LONG_ORDER_ID_INDEX.clear();
        SHORT_ORDER_ID_INDEX.clear();
@@ -226,6 +234,8 @@
        for (GridElement e : INDEX.values()) {
            putDynamicIndices(e);
        }
        }
        // logAll 在锁外执行,不阻塞计数查询
        logAll();
    }