Java缓存使用ArrayList/HashMap的常见问题----ConcurrentModification

对于一些经常读取,但是很少写的数据,经常会使用缓存来存储。常见的做法是:

List<String> list = new ArrayList<String>();
Map<String,String> map = new HashMap<String,String>();
//if modify
public void modify() {
     synchronized(list){
         //do modify list
     } 
     synchronized(map){
        //do modify map
     }
}

这样的做法会有一些风险。因为list/map可能在另一个地方正在被迭代使用,比如:

Iterator<String> it = list.iterator();
while(it.hasNext()){ 
       //do things
}
for(String str : it){
      //do things
}

这个时候,会立即报ConcurrentModification的错误,而且错误发生的概率比较小,但是一旦出错,就会造成严重错误以致宕机,因为你肯定不会在迭代的地方try/catch该异常。原因是ArrayList和hashmap这些jdk1.5以下的集合使用的都是强一致性迭代器,见jdk描述:

he iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModification

然后它的建议是使用:

List list = Collections.synchronizedList(new ArrayList(...));
任何时候都有可能使用当前集合的迭代器,所以必须在初始化的时候就同步好所有方法,但这样不是就等于退化到Hashtable了吗?其实就是没有高效的解决办法。

为了解决这个问题,在jdk1.5以后的concurrent集合里面,所有的实现都使用了弱一致性迭代器,不会抛ConcurrentModification错误。

所以,尽量使用ConcurrentHashMap和CopyOnWriteArrayList。他们使用了细粒度锁或者直接读写分离,非常适合读多写少的场景。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值