英文:
Proper way of truncating a synchronized ArrayList in Java
问题
I have a Java ArrayList that a process is filling it up with data:
synchronized (transferredFilesList) {
transferredFilesList.add(transferredFilesDataEvent);
}
I have another process that empties this list in such a way that, if the number of records in the list does not exceed 2500, it will remove all entries, but if the number of entries is greater than 2500, it should truncate the list so that the first 2500 entries are removed. I'm doing the truncation like this:
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.addAll(transferredFilesList.subList(0, 2500));
transferredFilesList.subList(0, 2500).clear();
}
}
But, whenever I exceed 2500 records, I'm getting a "java.util.ConcurrentModificationException," meaning that the code in the "else" block is not correct. What is the proper way of truncating a synchronized list without iterating and removing the elements one by one?
英文:
I have a Java ArrayList that a process is filling it up with data:
synchronized (transferredFilesList) {
transferredFilesList.add(transferredFilesDataEvent);
}
I have another process that empties this list in such a way that, if the number of records in the list does not exceed 2500, it will remove all entries, but if the number of entries is greater than 2500, it should truncate the list so that the first 2500 entries are removed. I'm doing the truncation like this:
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());
}
}
But, whenever I exceed 2500 records, I'm getting a "java.util.ConcurrentModificationException", meaning that the code in the "else" block is not correct. What is the proper way of truncating a synchronized list, without iterating and removing the elements one by one?
答案1
得分: 1
问题出在于你正在重新分配你要同步的对象。一旦这样做,synchronized
块就不再等待相同的监视器。
处理这个问题最简单的方法是避免重新分配,可以通过截取列表的头部来实现:
List<T> head = new ArrayList<>(list.subList(0, 2500));
list.subList(0, 2500).clear();
这不会创建一个新的列表,而是将列表截取到第 2500 个元素。
英文:
The problem you've got here is that you're reassigning the thing you are synchronizing on. As soon as you do that, synchronized
blocks are no longer waiting on the same monitor.
The easiest way to deal with this is to avoid the reassignment, by truncating the head of the list:
List<T> head = new ArrayList<>(list.subList(0, 2500));
list.subList(0, 2500).clear();
This doesn't create a new list, it just chops everything up to element 2500.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论