Обновление Монго выбрасывает ConcurrentModificationException? - PullRequest
1 голос
/ 22 февраля 2012

Я ищу много методов для решения проблем в течение длительного времени, но методы также не могут решить мою проблему, поэтому вам нужна ваша помощь, чтобы решить эту проблему, большое спасибо!

Стек исключений:

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

Ответы [ 2 ]

1 голос
/ 22 февраля 2012

Недостаточно информации, чтобы быть уверенным, но я подозреваю , что ваше приложение является многопоточным, и что какой-то другой поток обновляет BasicDBObject, пока текущий поток вызывает updateToMongo.

Нет волшебного решения для этого.Вы должны запретить другим потокам обновлять копию в памяти, пока вы сохраняете ее.


Да, мое приложение является многопоточным, но каждый поток, вызывающий updateToMongo в новом классе, затем BasicDBObject будет влиять на метод updateToMongo?

Я не знаюНе думаю, что уместно, чтобы вызовы updateToMongo происходили «в» другом классе или другом экземпляре.Проблема возникает (я предполагаю), потому что один поток обновляет данный экземпляр BasicDBObject, в то время как другой поток пытается сохранить тот же экземпляр.(Теоретически это может быть даже тот же поток, который делает это ... но этот сценарий немного надуманен.)

0 голосов
/ 22 февраля 2012

Вы используете цикл 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.
   ...
}

Однако, если вы изменяете набор точек во время итерации, вы можете пропустить некоторые данные и не узнаете об этом: 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);
   }
}

Обернуть любой код, который изменяет асинхронность «точек» в том же синхронизированном блоке. Также убедитесь, что вы синхронизируете, используя один и тот же объект блокировки.

Вы также можете использовать итератор (вообще не рекомендуется) или цикл while, но в конце они делают то же самое, что и цикл for, и, вероятно, менее эффективны.

Я точно не следовал приведенной трассировке стека, но она кое-что говорит об обновлениях точек, поэтому я надеюсь, что я не опубликовал полностью несвязанный материал. :)

...