迭代器和嵌套哈希表的Java并发问题

迭代器和嵌套哈希表的Java并发问题,java,multithreading,concurrency,Java,Multithreading,Concurrency,早上好,希望能得到比我更了解Java的人的帮助。我来自.NET背景,一直负责跟踪供应商提供的解决方案中的问题。我相信我已经找到了,但如果可能的话,我想听听第二、第三或第四种意见 我认为正在发生的是,第108行(在下面的代码块中指示)正在修改在while循环外部声明的迭代器(memIter)。他们通过更改在循环内部声明的实例而不是原始对象来修改它,我相信它会抛出,因为在修改后的集合/hastbale的第二次迭代中调用了“next”。我在这个网站上找到了许多指向这个问题的帖子(http://stac

早上好,希望能得到比我更了解Java的人的帮助。我来自.NET背景,一直负责跟踪供应商提供的解决方案中的问题。我相信我已经找到了,但如果可能的话,我想听听第二、第三或第四种意见

我认为正在发生的是,第108行(在下面的代码块中指示)正在修改在while循环外部声明的迭代器(memIter)。他们通过更改在循环内部声明的实例而不是原始对象来修改它,我相信它会抛出,因为在修改后的集合/hastbale的第二次迭代中调用了“next”。我在这个网站上找到了许多指向这个问题的帖子(http://stackoverflow.com/questions/602636/concurrentmodificationexception-and-a-hashmap)但是因为它是在集合中修改集合(如果这些是.net术语,那么很抱歉)(它是从迭代器中某个项的属性hastable中删除成员)我假设同样的逻辑也适用,但这不是我的空间。另外,如果我的假设是正确的,那么有人能提供正确的实现吗

堆叠

java.util.ConcurrentModificationException 堆栈跟踪: java.util.ConcurrentModificationException 位于java.util.HashMap$HashIterator.nextery(HashMap.java:793) 在java.util.HashMap$ValueIterator.next(HashMap.java:822) 在xxx.xxxxx.xx.xxxxxxx.end(RoleOrganizer.java:108) 地址:XXXXXXXX.java:568 位于xxx.xxxx.xxxxxxx.handleRequest(xxxxHandler.java:74) 位于com.xxxxx.server.JavaInstanceMethod.execute(JavaInstanceMethod.java:33) 在xx.xxxxxx.execute(AppServer.java:1469) 在xxx.xx.executeRequest(xxxxx java:1269) 在xxx.xxxxx.server.xxxx.doGet(xxxxx.java:350) 位于javax.servlet.http.HttpServlet.service(HttpServlet.java:690) 位于javax.servlet.http.HttpServlet.service(HttpServlet.java:803) 位于org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) 位于org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 位于org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 位于org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) 位于org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) 位于org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 位于org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 位于org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286) 位于org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190) 位于org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:283) 位于org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:767) 位于org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:697) 位于org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:889) 位于org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690) 运行(Thread.java:619)

下面的代码显示堆栈错误行号108

第87行 anpublic void end()

{

第99行
while(iter.hasNext())

第108行
StoreMember mem=(StoreMember)memIter.next()


当然,这听起来像是在迭代集合时更改集合的问题,尽管在没有看到
doTask
lookUpMembers
的情况下准确地跟踪正在发生的事情是很困难的(请注意,相同的逻辑也适用于.NET)

两种可能的修复方法(仅适用于一种!):

  • 复制
    lookUpMembers
    本身或使用它的位置中的
    lookUpMembers
    结果。从中创建一个新列表,然后从原始集合中删除项目就无关紧要了
  • 在循环中创建要删除的角色列表,然后再次单独循环以删除它们

就个人而言,我可能会选择第一个,因为这意味着您只需要进行一次更改听起来不像是由原始集合直接支持的。无论哪种方式,您都应该清楚地记录您正在做的事情。

在对集合进行迭代时,您不能修改它。解决方案是使用迭代器对象,并直接对其调用remove

使用ConcurrentHashMap会有所帮助,因为它不会引发ConcurrentModificationException。从ConcurrentHashMap:

检索操作(包括get) 通常不堵塞,因此可能会重叠 具有更新操作(包括put) 和删除)。检索反映了 最近完成的调查结果 更新保留在其上的操作 开始。对于聚合操作,例如 一目了然,同时 检索可能反映插入或删除 仅删除一些条目。 类似地,迭代器和枚举 返回反映状态的元素 在或处的某个点的哈希表的 自 迭代器/枚举 抛出ConcurrentModificationException。 然而,迭代器被设计成 一次只能由一个线程使用

我认为正在发生的是第108行(在下面的代码块中指示)正在修改迭代器

我怀疑您误解了在什么情况下会出现
ConcurrentModificationException

ConcurrentModificationException
不是由于con
Iterator iter = new ArrayList(this.m_member.getRoles()).iterator();

while (iter.hasNext())

{

  UserType rt = (UserType)iter.next();
  if (!this.m_roleMap.containsKey(rt.getGID()))
  {
    this.m_member.removeRole(ut);
  }
}
iter = this.m_roleMap.values().iterator();
{
  UserType ut = (UserType)iter.next();
  if (ut.isUnique())
  {
    Iterator memIter = this.m_member.doTask().lookUpMembers().iterator();
    while (memIter.hasNext())
    {
      if (mem.doWork() != this.m_member.getId())
      {
        if ((mem.hasRole(ut)) && (!mem.isFormer()))
        {
          mem.removeRole(ut);
        }
      }
    }
  }