簡體   English   中英

更新mongo引發ConcurrentModificationException嗎?

[英]update mongo throws ConcurrentModificationException?

我尋找了很多解決問題的方法很長時間,但是這些方法也無法解決我的問題,因此需要您的幫助來解決此問題,非常感謝!

異常堆棧:

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)

設置更新密鑰:

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);

更新密鑰到mongo:

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而當前線程正在調用updateToMongo

沒有任何神奇的解決方案。 持久存儲時,必須停止其他線程更新內存中的副本。


是的,我的應用程序是多線程的,但是每個線程在新類中調用updateToMongo時,BasicDBObject會影響updateToMongo方法嗎?

我認為對updateToMongo的調用發生在“不同的類或不同的實例中”並不重要。 問題正在發生(我猜是因為),一個線程正在更新給定的BasicDBObject實例,而另一個線程正在嘗試保留同一實例。 (理論上,這樣做甚至可能是同一線程……但是這種情況有些牽強。)

您正在使用for-each循環來遍歷“點”集合。 如果您的應用程序是多線程的,並且您修改(添加,刪除等)“點”集合,則將收到此錯誤。

您有兩種選擇。 首先,是使用常規的for循環並使用當前索引檢索對象。

for (int i = 0; i < points.size(); i++) {
   PointBasic p = points.get(i); // could be different depending upon your collection type.
   ...
}

但是,如果您在迭代時確實修改了點集合,則可能會跳過一些數據,而您可能會不了解:O
如果必須執行此操作,請嘗試同步代碼。
(同步代碼可確保包裝在同一塊中的代碼永遠不會在線程之間同時執行。)

<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);
   }
}

將所有修改“點”異步的代碼包裝在同一同步塊中。 另外,請確保使用相同的鎖定對象進行同步。

您也可以使用Iterator(完全不建議使用)或while循環,但最終它們會執行與for循環相同的操作,並且效率可能較低。

我沒有完全按照給出的堆棧跟蹤進行操作,但是它確實說明了有關更新點的信息,因此我希望我不會發布完全無關的材料。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM