2012-02-22 69 views
0

我搜索了很多方法來解決這個問題很久了,但是這個方法也解決不了我的問題,所以需要你的幫助來解決這個問題,非常感謝你!更新mongo拋出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; 
} 

回答

1

沒有足夠的信息可以確定,但我懷疑您的應用程序是多線程的,而其他某個線程正在更新BasicDBObject,而當前線程正在調用updateToMongo

這沒有什麼神奇的解決方案。您必須在其他線程停止更新內存副本的同時保留它。


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

我不認爲這是相關的,要updateToMongo呼叫發生「在」不同類別或不同的實例。問題正在發生(我猜),因爲一個線程正在更新給定的BasicDBObject實例,而另一個線程正試圖保持同一個實例。 (理論上它甚至可以是同一個線程這樣做......但是這種情況有點牽強附會。)

+0

是的,我的應用程序是多線程的,但是每個線程在新類中調用updateToMongo,那麼BasicDBObject會影響updateToMongo方法嗎?謝謝 ! – dawnsky 2012-02-22 06:39:19

+0

是的,你是對的,MongoDatabaseUtil是一個Singleton,當我調用方法updateToMongo – dawnsky 2012-02-22 08:37:57

0

您正在使用for-each循環遍歷「points」集合。 如果你的應用程序是多線程的,你修改(添加,刪除等)'點'集合,你會得到這個錯誤。

你有幾個選項。 首先,使用常規循環並檢索具有當前索引的對象。

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循環相同的操作,效率可能更低。

我並沒有完全按照給定的堆棧跟蹤,但它確實說了更新點的內容,所以我希望我沒有發佈完全不相關的材料。 :)

+0

時,and將只獲得一個帶有collName的DBCollection。是的,我認爲其他響應正確。這個問題看起來並不是來自堆棧跟蹤的代碼的for循環,而是BasicDBObject是從HashMap派生的,而HashMap不是線程安全的。 – 2012-02-22 04:24:31

+0

@ScottHernandez - 這不完全是一個線程安全問題。 'HashMap'可以是線程安全的,*仍然*不支持與迭代同時進行修改。 – 2012-02-22 04:42:42

+0

@ScottHernandez你可能是對的,我在使用foreach循環時遇到過這個異常,當我看到foreach循環遍歷一個沒有包含在他提供的代碼中的列表時,誰知道他可能在哪裏使用它。 – 2012-02-22 04:54:02