Proper way of truncating a synchronized ArrayList in Java

huangapple go评论79阅读模式
英文:

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&lt;LinkedHashMap&lt;String, Object&gt;&gt; tempTransferredFilesList;
synchronized (transferredFilesList) {
	logger.info(&quot;Transferred files list size: &quot; + transferredFilesList.size());
	if(transferredFilesList.size() &lt; 2500){
		tempTransferredFilesList = transferredFilesList;
		transferredFilesList = new ArrayList&lt;LinkedHashMap&lt;String, Object&gt;&gt;();
	}else{
		tempTransferredFilesList = new ArrayList&lt;LinkedHashMap&lt;String, Object&gt;&gt;();
		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&lt;T&gt; head = new ArrayList&lt;&gt;(list.subList(0, 2500));
list.subList(0, 2500).clear();

This doesn't create a new list, it just chops everything up to element 2500.

huangapple
  • 本文由 发表于 2020年8月12日 22:32:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/63378754.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定