java.util.ConcurrentModificationException

Map goodsProfileMap;
synchronized(this)
{
if(goodsProfileCache.get(cityId) == null)
{
goodsProfileMap = goodsProfileReader.getOnlineGoodsProfileByCity(cityId);
goodsProfileCache.put(cityId, goodsProfileMap);
}
else
{
goodsProfileMap = goodsProfileCache.get(cityId);

}

}
logger.info("online goods in city : " + cityId + ", count : " + goodsProfileMap.size());

ArrayList serviceList = new ArrayList();
ArrayList commodityList = new ArrayList();
if(goodsProfileMap == null)
{
logger.info("no new goods in city : " + cityId + " for user : " + uid);
return null;
}

// remove these goods that have been already bought by the user
Set buyGoodsSet = userProfile.getBuyGoodsIdSet();
for(int goodsId : buyGoodsSet)   //片段1
{
goodsProfileMap.remove(goodsId);
}
Collection coll = goodsProfileMap.values();


long time1 = System.currentTimeMillis();
for(GoodsProfile goodsProfile:coll)             //片段2
{
int cate = goodsCategoryReader.getType(goodsProfile.getNewcate());
GoodsRank goodsRank = new GoodsRank(goodsProfile);
if(cate == 1)
{
serviceList.add(goodsRank);
}
else
{
commodityList.add(goodsRank);
}

}

上面的代码在多线程环境中执行会出现ConcurrentModificationException,原因在于一个线程在执行片段2时,可能会碰到其他线程在执行片段1。迭代器在对List进行迭代时要求其元素不能被修改。原因可以参考http://www.blogjava.net/EvanLiu/archive/2008/08/31/224453.html

代码中另一个错误是:没有考虑到java里面的引用机制(即c++的浅拷贝,c++默认也是浅拷贝),所以每个线程过来后都会对同一个goodsProfileMap进行修改,这样就间接造成了上面的错误。

正确的代码可以改为:

Map goodsProfileMap = new HashMap();
synchronized(this)
{
if(goodsProfileCache.get(cityId) == null)
{
Map gpm = goodsProfileReader.getOnlineGoodsProfileByCity(cityId);
goodsProfileCache.put(cityId, gpm);
goodsProfileMap.putAll(gpm);
}
else
{
goodsProfileMap.putAll(goodsProfileCache.get(cityId));

}

}
logger.info("online goods in city : " + cityId + ", count : " + goodsProfileMap.size());

ArrayList serviceList = new ArrayList();
ArrayList commodityList = new ArrayList();
if(goodsProfileMap == null)
{
logger.info("no new goods in city : " + cityId + " for user : " + uid);
return null;
}

// remove these goods that have been already bought by the user
Set buyGoodsSet = userProfile.getBuyGoodsIdSet();
for(int goodsId : buyGoodsSet)
{
goodsProfileMap.remove(goodsId);
}
Collection coll = goodsProfileMap.values();


long time1 = System.currentTimeMillis();
for(GoodsProfile goodsProfile:coll)
{
int cate = goodsCategoryReader.getType(goodsProfile.getNewcate());
GoodsRank goodsRank = new GoodsRank(goodsProfile);
if(cate == 1)
{
serviceList.add(goodsRank);
}
else
{
commodityList.add(goodsRank);
}
}


你可能感兴趣的:(java)