首页 > 解决方案 > 在 Java 中截断同步 ArrayList 的正确方法

问题描述

我有一个 Java ArrayList,一个进程正在用数据填充它:

synchronized (transferredFilesList) {
    transferredFilesList.add(transferredFilesDataEvent);
}

我有另一个进程清空这个列表,如果列表中的记录数不超过 2500,它将删除所有条目,但如果条目数大于 2500,它应该截断列表所以删除前 2500 个条目。我正在做这样的截断:

List<LinkedHashMap<String, Object>> tempTransferredFilesList;
synchronized (transferredFilesList) {
    logger.info("Transferred files list size: " + transferredFilesList.size());
    if(transferredFilesList.size() < 2500){
        tempTransferredFilesList = transferredFilesList;
        transferredFilesList = new ArrayList<LinkedHashMap<String, Object>>();
    }else{
        tempTransferredFilesList = new ArrayList<LinkedHashMap<String, Object>>();
        tempTransferredFilesList = transferredFilesList.subList(0, 2500);
        transferredFilesList = transferredFilesList.subList(2500, transferredFilesList.size());
    }
}

但是,每当我超过 2500 条记录时,我都会收到“java.util.ConcurrentModificationException”,这意味着“else”块中的代码不正确。在不逐个迭代和删除元素的情况下截断同步列表的正确方法是什么?

标签: javaarrayssynchronizationsynchronized

解决方案


你在这里遇到的问题是你正在重新分配你正在同步的东西。一旦你这样做了,synchronized块就不再在同一个监视器上等待。

处理这个问题的最简单方法是通过截断列表的头部来避免重新分配:

List<T> head = new ArrayList<>(list.subList(0, 2500));
list.subList(0, 2500).clear();

这不会创建一个新列表,它只是将所有内容切到元素 2500。


推荐阅读