Java 更新mongo抛出ConcurrentModificationException?

Java 更新mongo抛出ConcurrentModificationException?,java,mongodb,exception,map,mongo-java,Java,Mongodb,Exception,Map,Mongo Java,我寻找了很多方法来解决问题很久了,但是这些方法也不能解决我的问题,所以需要你的帮助来解决这个问题,非常感谢 异常堆栈: java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:977) at java.util.HashMap$KeyIterator.next(HashMap.java:1012) at org.bson.BSONEncoder.putIt

我寻找了很多方法来解决问题很久了,但是这些方法也不能解决我的问题,所以需要你的帮助来解决这个问题,非常感谢

异常堆栈:

java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:977)
at java.util.HashMap$KeyIterator.next(HashMap.java:1012)
at org.bson.BSONEncoder.putIterable(BSONEncoder.java:258)
at org.bson.BSONEncoder._putObjectField(BSONEncoder.java:198)
at org.bson.BSONEncoder.putObject(BSONEncoder.java:140)
at org.bson.BSONEncoder._putObjectField(BSONEncoder.java:190)
at org.bson.BSONEncoder.putIterable(BSONEncoder.java:259)
at org.bson.BSONEncoder._putObjectField(BSONEncoder.java:198)
at org.bson.BSONEncoder.putObject(BSONEncoder.java:140)
at org.bson.BSONEncoder._putObjectField(BSONEncoder.java:190)
at org.bson.BSONEncoder.putObject(BSONEncoder.java:140)
at org.bson.BSONEncoder.putObject(BSONEncoder.java:86)
at com.mongodb.OutMessage.putObject(OutMessage.java:190)
at com.mongodb.DBApiLayer$MyCollection.update(DBApiLayer.java:341)
at com.mongodb.DBCollection.update(DBCollection.java:150)
at com.autonavi.sns.util.TileCache.updateToMongo(TileCache.java:589)
at com.autonavi.sns.util.TileCache.updatePoint(TileCache.java:349)
at com.autonavi.sns.workflow.function.UpdatePointFunc.updatePoint(UpdatePointFunc.java:82)
at com.autonavi.sns.workflow.function.UpdatePointFunc.doExec(UpdatePointFunc.java:37)
at com.autonavi.sns.workflow.function.SNSFunction.execFunc(SNSFunction.java:42)
at com.autonavi.sns.workflow.function.SNSFunction.execFunc(SNSFunction.java:45)
at com.autonavi.sns.workflow.function.SNSFunction.execFunc(SNSFunction.java:45)
at com.autonavi.sns.workflow.function.SNSFunction.execFunc(SNSFunction.java:45)
at com.autonavi.sns.workflow.function.SNSFunction.execFunc(SNSFunction.java:45)
at com.autonavi.sns.workflow.SNSWorkFlow.startExec(SNSWorkFlow.java:45)
at com.autonavi.sns.workflow.SNSWorkFlow.execute(SNSWorkFlow.java:31)
at com.autonavi.sns.service.SNSThreadHandler.serviceDispacth(SNSThreadHandler.java:79)
at com.autonavi.sns.service.SNSThreadHandler.run(SNSThreadHandler.java:47)
at java.lang.Thread.run(Thread.java:662)
private boolean updateToMongo(BasicDBObject udbo, BasicDBObject ukey, long layer) {
    boolean flag = false;
    try {
        this.mongo = MongoDatabaseUtil.getInstance();
        this.coll = mongo.getCollection(ConstantUtil.TILE_COLL + layer);
        this.coll.update(udbo, ukey, true, true);
        flag = true;
    } catch (MongoException e) {
        LOG.error("Mongo error : ", e);
    }

    return flag;
}
设置更新密钥:

BasicDBObject udbo = new BasicDBObject();
udbo.put(ConstantUtil.MONGO_ID_KEY, tileId);

List<BasicDBObject> plist = new ArrayList<BasicDBObject>();
for (PointBasic p : points) {
    BasicDBObject pkey = new BasicDBObject();
    boolean isPhysic = p.isPhysicPoint();
    pkey.put("isphysic", isPhysic);
    pkey.put("x", p.getX());
    pkey.put("y", p.getY());
    pkey.put("picurl", p.getPicUrl());
    pkey.put("area", p.getArea());
    plist.add(pkey);
}

BasicDBObject pdbo = new BasicDBObject();
pdbo.put("$set", new BasicDBObject("point", plist));

return this.updateToMongo(udbo, pdbo, TILE_LAYER);

没有足够的信息可以确定,但我怀疑您的应用程序是多线程的,并且当当前线程调用
updateMongo
时,其他线程正在更新
BasicDBObject

没有什么神奇的解决办法。在持久化内存中副本时,必须阻止其他线程更新该副本



是的,我的应用程序是多线程的,但是每个线程在一个新类中调用updateToMongo,那么BasicDBObject会影响updateToMongo方法吗


我认为对
updateMongo
的调用“发生在”不同的类或不同的实例中并不相关。问题发生了(我猜是这样),因为一个线程正在更新给定的
BasicDBObject
实例,而另一个线程正在尝试持久化同一实例。(理论上可能是同一个线程执行此操作……但这种情况有点牵强。)

您正在使用for-each循环来迭代您的“points”集合。 如果您的应用程序是多线程的,并且您修改(添加、删除等)了“points”集合,则会出现此错误

你有几个选择。 首先,是使用常规for循环并检索具有当前索引的对象

for (int i = 0; i < points.size(); i++) {
   PointBasic p = points.get(i); // could be different depending upon your collection type.
   ...
}
for(int i=0;i
但是,如果在迭代时确实修改了points集合,则可能会跳过一些数据,而您对此一无所知:O
如果此操作是强制性的,请尝试同步代码。
(同步代码可确保包装在同一块中的代码不会在线程之间同时执行。)


私有对象点lock=new Object();
已同步(点锁定){
对于(点基本p:点){
BasicDBObject pkey=新的BasicDBObject();
布尔值isPhysic=p.isPhysicPoint();
pkey.put(“isphysic”,isphysic);
pkey.put(“x”,p.getX());
pkey.put(“y”,p.getY());
put(“picurl”,p.getPicUrl());
pkey.put(“area”,p.getArea());
plist.add(pkey);
}
}
将修改异步“点”的任何代码包装在同一个同步块中。 另外,请确保使用相同的锁定对象进行同步

您也可以使用迭代器(一点也不推荐),或while循环,但最终它们所做的事情与for循环大致相同,并且可能效率较低


我没有完全遵循给出的堆栈跟踪,但它确实说明了一些关于更新点的信息,所以我希望我没有发布完全无关的材料。:)

是的,我想另一个回答是正确的。问题看起来不在堆栈跟踪代码的for循环中,但BasicDBObject是从HashMap派生的,它不是线程安全的。@ScottHernandez-这不完全是线程安全问题
HashMap
可能是线程安全的,但仍然不支持与迭代同时进行的修改。@ScottHernandez您可能是对的,我在使用foreach循环时经历了很多这种异常,当我看到foreach循环在他提供的代码中未包含的列表上迭代时,谁知道他可能在哪里使用它。是的,我的应用程序是多线程的,但是每个线程在一个新类中调用UpdateMongo,那么BasicDBObject会影响UpdateMongo方法吗?非常感谢。是的,您是对的,MongoDatabaseUtil是一个单例,当我调用updateToMongo方法时,and将只获得一个collName的DBCollection
<global>
private Object pointsLock = new Object();
</global>

synchronized (pointsLock) {
   for (PointBasic p : points) {
      BasicDBObject pkey = new BasicDBObject();
      boolean isPhysic = p.isPhysicPoint();
      pkey.put("isphysic", isPhysic);
      pkey.put("x", p.getX());
      pkey.put("y", p.getY());
      pkey.put("picurl", p.getPicUrl());
      pkey.put("area", p.getArea());
      plist.add(pkey);
   }
}