在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”块中的代码是不正确的。在不逐一迭代和删除元素的情况下,截断同步列表的正确方法是什么?

解决方法

这里遇到的问题是您要重新分配要同步的对象。一旦这样做,synchronized块将不再在同一监视器上等待。

处理此问题的最简单方法是通过缩短列表的开头来避免重新分配:

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

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