DWR同時異常

6969 ワード


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)

 , sessionMap , modCount expectedModCount , checkForComodification() , 
 protected void checkTimeouts()
    {
        long now = System.currentTimeMillis();
        List timeouts = new ArrayList();

        synchronized (sessionLock)
        {
            for (Iterator it = sessionMap.values().iterator(); it.hasNext();)
            {
                DefaultScriptSession session = (DefaultScriptSession) it.next();

                if (session.isInvalidated())
                {
                    continue;
                }

                long age = now - session.getLastAccessedTime();
                if (age > scriptSessionTimeout)
                {
                    timeouts.add(session);
                }
            }

            for (Iterator it = timeouts.iterator(); it.hasNext();)
            {
                DefaultScriptSession session = (DefaultScriptSession) it.next();
                session.invalidate();
            }
        }
    }

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

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();

http://pengtyao.iteye.com/blog/1074271
conCurrentHashMap iterator 
http://stackoverflow.com/questions/3768554/is-iterating-concurrenthashmap-values-thread-safe