【问题标题】:ConcurrentModificationException when reading from GAE Datastore using JDO使用 JDO 从 GAE 数据存储读取时出现 ConcurrentModificationException
【发布时间】:2013-09-22 03:21:33
【问题描述】:

我正在查询 GAE 数据存储以检索实体列表(使用带有 sdk 1.8.3 的 dev gae):

public List<OT> getAll() {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    Query q = pm.newQuery();
    q.setClass(OT.class);
    try {
        return (List<OT>) q.execute();
    }
    finally {
        q.closeAll();
        pm.close();
    }
}

这总是在pm.close() 行上抛出一个ConcurrentModificationException

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
    at java.util.ArrayList$Itr.next(ArrayList.java:791)
    at com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl$DatastoreManagedConnection.close(DatastoreConnectionFactoryImpl.java:146)
    at org.datanucleus.store.connection.ConnectionManagerImpl.closeAllConnections(ConnectionManagerImpl.java:181)
    at org.datanucleus.store.AbstractStoreManager$1.preClose(AbstractStoreManager.java:260)
    at org.datanucleus.ObjectManagerImpl.close(ObjectManagerImpl.java:1112)
    at org.datanucleus.api.jdo.JDOPersistenceManager.internalClose(JDOPersistenceManager.java:359)
    at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.releasePersistenceManager(JDOPersistenceManagerFactory.java:1106)
    at org.datanucleus.api.jdo.JDOPersistenceManager.close(JDOPersistenceManager.java:343)

我正在使用以下依赖项:

    <dependency>
        <groupId>com.google.appengine.orm</groupId>
        <artifactId>datanucleus-appengine</artifactId>
        <version>2.0.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.datanucleus</groupId>
        <artifactId>datanucleus-core</artifactId>
        <version>3.1.3</version>
    </dependency>
    <dependency>
        <groupId>org.datanucleus</groupId>
        <artifactId>datanucleus-api-jdo</artifactId>
        <version>3.1.3</version>
    </dependency>
    <dependency>
        <groupId>javax.jdo</groupId>
        <artifactId>jdo-api</artifactId>
        <version>[3.0, 4.0)</version>
    </dependency>
    <dependency>
        <groupId>org.datanucleus</groupId>
        <artifactId>datanucleus-rdbms</artifactId>
        <version>3.1.3</version>
        <scope>runtime</scope>
    </dependency>

以及以下版本的 DN 增强器:

    <dependency>
        <groupId>org.datanucleus</groupId>
        <artifactId>datanucleus-enhancer</artifactId>
        <version>3.1.1</version>
    </dependency>

我不会对集合中的任何对象或集合本身进行任何修改。事实上,即使集合为空,也会发生错误...... 知道我可能做错了什么吗?

其他调试细节 我在 pm.close() 语句中进入了调试模式,发现在迭代侦听器时,其中一个正在从侦听器列表中删除自己:

447468239@qtp-1694835335-71@11277, prio=5, in group 'main', status: 'RUNNING'
  at org.datanucleus.store.connection.ConnectionManagerImpl$1.managedConnectionPostClose(ConnectionManagerImpl.java:247)
  at com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl$DatastoreManagedConnection.close(DatastoreConnectionFactoryImpl.java:147)
  at org.datanucleus.store.connection.ConnectionManagerImpl.closeAllConnections(ConnectionManagerImpl.java:181)
  at org.datanucleus.store.AbstractStoreManager$1.preClose(AbstractStoreManager.java:260)
  at org.datanucleus.ObjectManagerImpl.close(ObjectManagerImpl.java:1112)
  at org.datanucleus.api.jdo.JDOPersistenceManager.internalClose(JDOPersistenceManager.java:359)
  at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.releasePersistenceManager(JDOPersistenceManagerFactory.java:1106)
  at org.datanucleus.api.jdo.JDOPersistenceManager.close(JDOPersistenceManager.java:343)
  at net.mycrub.jacasse.persistence.dao.GenericDAO.getAll(GenericDAO.java:43)

ConnectionManagerImpl.java:247 处的代码

                    // Remove this listener
                    mconn.removeListener(this);

这不是我自己添加的监听器。它实际上是在Query.closeAll() 语句中添加的DN 侦听器。我应该保留这两个“关闭”语句中的任何一个,它们是多余的吗?

【问题讨论】:

  • 有点难以判断您发布的摘录发生了什么。通常ConcurrentModificationExceptions 发生在 arraylist 有多个迭代器对其进行迭代的任何时候,无论它们是否实际修改了其中的任何内容。
  • 感谢您的回答。问题是它在我尝试迭代之前就已经发生了。

标签: java google-app-engine google-cloud-datastore jdo datanucleus


【解决方案1】:

你尝试过这样的事情吗?

public List<OT> getAll()
{
  List<OT> liResult = null;

  PersistenceManager pm = PMF.get().getPersistenceManager();
  Query q = pm.newQuery();
  try
  {
    q.setClass(OT.class);
    liResult = (List<OT>)q.execute();
  }
  finally
  {
    try
    {
      q.closeAll();
    }
    finally
    {
      pm.close();
    }
  }

  return liResult;
}

【讨论】:

  • 老实说,我现在已经切换到 Objectify,它负责处理复杂的接线问题。以后有空的时候我可能会测试你的代码。
【解决方案2】:

DatastoreManagedConnection#close() 方法很简单

public void close() {
    for (ManagedConnectionResourceListener listener : listeners) {
        listener.managedConnectionPreClose();
    }
    // nothing to actually close
    for (ManagedConnectionResourceListener listener : listeners) {
        listener.managedConnectionPostClose();
    }
}

ConcurrentModificationException 不能直接来自这里,因为此代码中的任何内容都不会修改 listeners List。是否有可能您有其他代码并行运行并从listeners 添加或删除,调用addListenerremoveListener

【讨论】:

  • 谢谢,在调试模式下进行一些分析后,我在问题中添加了一些细节。
猜你喜欢
  • 2014-10-19
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 2017-03-04
  • 2014-02-09
  • 1970-01-01
  • 2013-03-04
  • 1970-01-01
相关资源
最近更新 更多