You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决内部用LinkedHashMap的LRUCache缩容时的ConcurrentModificationException

解决LRUCache缩容时的ConcurrentModificationException问题

针对你遇到的并发场景下调用iter.remove()抛出异常的问题,提供几个可行的解决方案:

1. 加全局锁同步所有操作

并发修改和迭代操作互斥是最直接的解决方式,给所有涉及缓存结构修改或迭代的方法加上同一把锁:

private final Object lock = new Object();

protected void shrinkSize() {
    synchronized(lock) {
        Iterator iter = fetchIterator();
        while (iter.hasNext()) {
            if (size() > maxSize) {
                iter.remove();
            } else {
                break;
            }
        }
    }
}

// 所有修改缓存结构或调整LRU顺序的方法(如get、put、remove)都要加同一锁
public Object get(Object key) {
    synchronized(lock) {
        // 原get逻辑,包括将访问的条目移到LRU头部等操作
        return value;
    }
}

原理:锁确保迭代过程中,没有其他线程能修改缓存结构,从根本上避免并发修改导致的迭代器异常。

2. 使用支持弱一致性的并发迭代器

如果你的LRUCache底层改用支持fail-safe(弱一致性)的容器实现,这类容器的迭代器不会因为并发修改抛出ConcurrentModificationException,比如基于ConcurrentHashMap实现LRU的链表结构。此时缩容方法可以调整为:

protected void shrinkSize() {
    Iterator iter = fetchConcurrentIterator();
    // 循环判断直到容量符合要求,因为迭代器是弱一致性的,可能看不到实时修改
    while (size() > maxSize && iter.hasNext()) {
        iter.remove();
    }
}

原理:弱一致性迭代器基于容器快照或分段锁实现,允许并发修改,不会抛出异常,但要注意迭代过程中可能无法立即感知到其他线程的修改,所以需要循环判断容量直到达标。

3. 复用LRU淘汰逻辑完成缩容

LRUCache本身就有淘汰最久未使用条目的逻辑,可以直接复用这个逻辑来完成缩容,避免单独的迭代操作:

protected void shrinkSize() {
    synchronized(lock) {
        // 循环移除最久未使用的条目,直到容量达标
        while (size() > maxSize) {
            removeLeastRecentlyUsed();
        }
    }
}

// 实现移除最久未使用条目的方法
private void removeLeastRecentlyUsed() {
    // 根据LRU的链表结构,移除尾部节点(最久未使用)
    // 具体实现根据你的LRUCache结构调整
}

原理:直接利用LRU的特性定位要移除的条目,不需要遍历整个缓存,效率更高,同时加锁确保并发安全。

内容的提问来源于stack exchange,提问作者sreenivas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:05:00