`
zyslovely
  • 浏览: 230307 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

DWR并发异常 java.util.ConcurrentModificationException checkTimeouts

 
阅读更多
52818 java.util.ConcurrentModificationException
52819     at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
52820     at java.util.HashMap$ValueIterator.next(HashMap.java:822)
52821     at org.directwebremoting.impl.DefaultScriptSessionManager.checkTimeouts(DefaultScriptSessionManager.java:179)
52822     at org.directwebremoting.impl.DefaultScriptSessionManager.maybeCheckTimeouts(DefaultScriptSessionManager.java:163)
52823     at org.directwebremoting.impl.DefaultScriptSessionManager.getScriptSession(DefaultScriptSessionManager.java:50)
52824     at org.directwebremoting.impl.DefaultWebContext.getScriptSession(DefaultWebContext.java:83)
52825     at org.directwebremoting.dwrp.BaseCallMarshaller.marshallOutbound(BaseCallMarshaller.java:305)
52826     at org.directwebremoting.servlet.PlainCallHandler.handle(PlainCallHandler.java:53)
52827     at org.directwebremoting.servlet.UrlProcessor.handle(UrlProcessor.java:101)
52828     at org.directwebremoting.servlet.DwrServlet.doPost(DwrServlet.java:146)
52829     at com.netease.photo.webapp.web.servlets.PhotoDwrServlet.doPost(PhotoDwrServlet.java:51)
52830     at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
52831     at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
52832     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
52833     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
52834     at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:265)
52835     at com.netease.photo.security.filter.NEAccessInfoFilter.doFilter(NEAccessInfoFilter.java:55)
52836     at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
52837     at com.netease.photo.security.filter.NEFilterSecurityInterceptor.doFilter(NEFilterSecurityInterceptor.java:49)
52838     at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
52839     at com.netease.photo.security.filter.NEAnonymousProcessingFilter.doFilter(NEAnonymousProcessingFilter.java:234)
52840     at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
52841     at com.netease.photo.security.filter.NEAuthenticationProcessingFilter.doFilter(NEAuthenticationProcessingFilter.java:300)
52842     at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
52843     at com.netease.photo.security.filter.NEExceptionTranslationFilter.doFilter(NEExceptionTranslationFilter.java:62)



查看源代码可以发现,异常代码块
/*     */   protected void checkTimeouts()
/*     */   {
/* 174 */     long now = System.currentTimeMillis();
/* 175 */     List timeouts = new ArrayList();
/*     */ 
/* 177 */     for (Iterator it = this.sessionMap.values().iterator(); it.hasNext(); )
/*     */     {
/* 179 */       DefaultScriptSession session = (DefaultScriptSession)it.next();
/*     */ 
/* 181 */       if (session.isInvalidated())
/*     */       {
/*     */         continue;
/*     */       }
/*     */ 
/* 186 */       long age = now - session.getLastAccessedTime();
/* 187 */       if (age > this.scriptSessionTimeout)
/*     */       {
/* 189 */         timeouts.add(session);
/*     */       }
/*     */     }
/*     */ 
/* 193 */     for (Iterator it = timeouts.iterator(); it.hasNext(); )
/*     */     {
/* 195 */       DefaultScriptSession session = (DefaultScriptSession)it.next();
/* 196 */       session.invalidate();
/*     */     }
/*     */   }


由于iterator报这个错是因为再iterator的过程中有添加删除操作
,查看添加删除sessionMap数据的代码
  public RealScriptSession getScriptSession(String id)
    {
        maybeCheckTimeouts();

        synchronized (sessionLock)
        {
            DefaultScriptSession scriptSession = (DefaultScriptSession) sessionMap.get(id);
            if (scriptSession == null)
            {
                scriptSession = new DefaultScriptSession(id, this);
              *  sessionMap.put(id, scriptSession);*
            }
            else
            {
                scriptSession.updateLastAccessedTime();
            }

            return scriptSession;
        }
    }
    protected void invalidate(RealScriptSession scriptSession)
    {
        // Can we think of a reason why we need to sync both together?
        // It feels like a deadlock risk to do so
        synchronized (sessionLock)
        {
            *RealScriptSession removed = (RealScriptSession) sessionMap.remove(scriptSession.getId());*
            if (!scriptSession.equals(removed))
            {
                log.debug("ScriptSession already removed from manager. scriptSession=" + scriptSession + " removed=" + removed);
            }

            int removeCount = 0;
            for (Iterator it = pageSessionMap.values().iterator(); it.hasNext();)
            {
                Set pageSessions = (Set) it.next();
                boolean isRemoved = pageSessions.remove(scriptSession);

                if (isRemoved)
                {
                    removeCount++;
                }
            }

            if (removeCount != 1)
            {
                log.debug("DefaultScriptSessionManager.invalidate(): removeCount=" + removeCount + " when invalidating: " + scriptSession);
            }
        }
    }


发现已经做了sessionlock,并且在其他外部类中没有调用。
http://directwebremoting.org/jira/browse/DWR-536
这个是我们遇到的问题.
The problem is when using an iterator of a synchonized map; when using an iterator, the map (even when it is synchronized) should be synchronized while iterating...
即使对hashmap外部做了synchronized,在iterator的时候hashmap还是不安全的。(这里不安全的原因还在调查,估计跟jvm有关)
有两种解决方案
1.对hashmap在iterator之前做一次拷贝
2.对hashmap做同步,可以使用concurrenthashmap

在dwr后面的几次版本更新中已经有了修改
/*     */   protected final ConcurrentMap sessionMap;
/*     */   protected final ConcurrentMap> pageSessionMap;

/* 527 */     this.sessionMap = new ConcurrentHashMap();
/*     */ 
/* 535 */     this.pageSessionMap = new ConcurrentHashMap();



为什么使用conCurrentMap能够保证安全?

首先,从问题代码讲起
for (Iterator it = sessionMap.values().iterator(); it.hasNext();)
出问题的原因是iterator在做浅拷贝的时候,sessionMap有数据变化(添加、删除)
导致modCount和expectedModCount不相等,判断了checkForComodification()后,抛出异常
在使用ConcurrentMap的时候,
ConcurrentHashMap使用了不同于传统集合的快速失败迭代器(见之前的文章《JAVA API备忘---集合》)的另一种迭代方式,我们称为弱一致迭代器。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。 

参考文献地址:
[url]http://pengtyao.iteye.com/blog/1074271[/url]
[url]http://stackoverflow.com/questions/3768554/is-iterating-concurrenthashmap-values-thread-safe[/url]

It is guaranteed that things will not break if you do this (that's part of what the "concurrent" in ConcurrentHashMap means). However, there is no guarantee that one thread will see the changes to the map that the other thread performs (without obtaining a new iterator from the map). The iterator is guaranteed to reflect the state of the map at the time of it's creation. Futher changes may be reflected in the iterator, but they do not have to be.


分享到:
评论

相关推荐

    dwr包.rar dwr.jar engine.js util.js dwr-noncla.jar readme.txt

    dwr包.rar dwr.jar engine.js util.js dwr-noncla.jar readme.txt JAR File: dwr.jar (1.08Mb) To DWR enable your web-app WAR File: dwr.war (4.62Mb) Demos/Examples of what DWR can do Sources: dwr-...

    dwr.jar engine.js util.js,Dwr相关

    标题中的"dwr.jar"是DWR的主要库文件,包含了所有必要的Java类和接口,用于在服务器端实现DWR的功能。这个JAR文件通常会被部署到应用服务器的类路径中,以便服务端代码可以访问和使用DWR的API。 "engine.js"是DWR的...

    dwr教程+dwr.jar+util.js+engine.js

    首先,`dwr.jar` 文件是DWR的主要库文件,包含了所有必要的类和接口,使得Java对象能够在浏览器中被调用。它简化了AJAX(Asynchronous JavaScript and XML)应用的开发,通过动态生成JavaScript,将服务器端的Java...

    DWR(包括engine.js+util.js).rar

    为了使用DWR,开发者需要在服务器端配置DWR引擎,定义允许访问的Java类和方法,并在客户端引入`engine.js`和`util.js`。然后,通过JavaScript代码就可以直接调用服务器端的方法,实现双向通信。 总之,DWR提供了一...

    DWR+jquery2.x+easyUI1.3.x开发富客户端应用

    ### DWR+jquery2.x+easyUI1.3.x开发富客户端应用 #### 知识点一:技术栈概述 本篇文章将介绍一种基于DWR、jquery2.x以及easyUI1.3.x的技术栈来构建富客户端应用的方法。该技术栈还包括了Struts2.x、Spring3.x等...

    dwr-3.0.jar

    最新dwr3.0的包,有需要的朋友就下载吧

    DWR-Getting Started.pdf

    - DWR Servlet接收到请求后,根据`dwr.xml`中的配置找到对应的Java类实例,并执行相应的操作。 - 处理结果会被序列化成JSON格式返回给客户端。 #### 六、总结 通过以上步骤,你可以成功地将DWR集成到现有的Web...

    xalan.jar dwr使用异常

    做个extjs 与dwr结合的例子dwr2.0 jdk6.0 dwr 取不到数据 困扰了我一天 后来下载了xalan.jar 包导入工程 ok 2009-8-16 10:18:39 org.directwebremoting.util.CommonsLoggingOutput info 信息: DWR Version 2.0.5 ...

    dwr3.0.0.116源码 part4

    dwr3.0.0.116源码 part4

    dwr20.dtd

    dwr20.dtd

    dwr.rar_dwr jar_dwr j_dwr jar_dwr.j_dwr.jar2

    标签中的"**dwr_j**"和"**dwr_jar**"可能指的是DWR的Java相关资源,而"**dwr.j**"可能是误写或者不完整的标签。"**dwr.jar2**"可能是另一个版本的DWR库,可能是更新后的版本,或者是一个备份文件。 在压缩包中的"**...

    dwr20.dtd约束文件

    dwr20.dtd约束文件。 <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://www.getahead.ltd.uk/dwr/dwr20.dtd" >

    dwr2.0.5.jar&dwr2.0.6.jar&dwr3.rc1.jar

    部署DWR JAR文件通常涉及到将它们添加到Web应用的类路径中,配置DWR的`dwr.xml`配置文件,以及在客户端HTML页面中引入相应的JavaScript库。对于Spring框架的集成,还需要配置Spring的bean定义。 总的来说,DWR的...

    dwr-1.1.1-util.js

    dwr-1.1.1-util.js

    springboot整合dwr实现js调用java方法

    4. **配置DWR映射**:在`dwr.xml`配置文件中,声明你想要暴露给JavaScript的Java类和方法。这个文件通常放在`src/main/resources`目录下。 ```xml <param name="class" value="com.example.DemoApplication....

    dwr3.0.0.116源码 part2

    dwr3.0.0.116源码 part2

    dwr util.js

    《DWR util.js详解及其应用》 DWR (Direct Web Remoting) 是一种在Web应用程序中实现客户端与服务器端通信的技术,它允许JavaScript代码直接调用Java方法,从而提供了更高效的异步数据交互。在DWR框架中,`util.js`...

    dwr五个例子.rar

    - `dwr.engine.js`和`dwr.util.js`:这两个JavaScript文件是DWR的核心库,提供与服务器交互的API。 3. **Java对象和JavaScript的交互**: - `RemoteObject`:DWR中的核心概念,表示在服务器上的Java对象。在...

    DWR中文文档......

    - **dwr.xml**:这个文件用于描述DWR服务的配置,包括哪些类和方法可以被远程调用,以及如何处理这些调用的细节。例如,通过`<allow>`标签指定允许远程访问的类和方法,通过`<converters>`和`<creators>`标签指定...

Global site tag (gtag.js) - Google Analytics