java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
at java.util.HashMap$KeyIterator.next(HashMap.java:823)
at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
at com.yy.forum.util.Cache.keys(Cache.java:239)
at com.yy.forum.OnlineManager.getUserIDtoArray(OnlineManager.java:48)
at com.yy.forum.OnlineManager.getBoardViewers(OnlineManager.java:89)
at org.apache.jsp.bbs.topicsList_jsp._jspService(topicsList_jsp.java:681)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:332)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.valves.FastCommonAccessLogValve.invoke(FastCommonAccessLogValve.java:495)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:199)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:282)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:754)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:684)
at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:876)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)

解决方案 »

  1.   

    我觉得出错的是Cache.java,代码为:
    package com.yy.forum.util;import java.util.*;
    import com.yy.forum.util.LinkedList;public class Cache implements Cacheable {    protected static long currentTime = CacheTimer.currentTime;    protected HashMap cachedObjectsHash;    protected LinkedList lastAccessedList;    protected LinkedList ageList;    protected int maxSize =  128 * 1024;    protected int size = 0;    protected long maxLifetime = -1;    protected long cacheHits, cacheMisses = 0L;    /**
         * Create a new cache with default values. Default cache size is 128K with
         * no maximum lifetime.
         */
        public Cache() {
            // Our primary data structure is a hash map. The default capacity of 11
            // is too small in almost all cases, so we set it bigger.
            cachedObjectsHash = new HashMap(103);        lastAccessedList = new LinkedList();
            ageList = new LinkedList();
        }    /**
         * Create a new cache and specify the maximum size for the cache in bytes.
         * Items added to the cache will have no maximum lifetime.
         *
         * @param maxSize the maximum size of the cache in bytes.
         */
        public Cache(int maxSize) {
            this();
            this.maxSize = maxSize;
        }    /**
         * Create a new cache and specify the maximum lifetime of objects. The
         * time should be specified in milleseconds. The minimum lifetime of any
         * cache object is 1000 milleseconds (1 second). Additionally, cache
         * expirations have a 1000 millesecond resolution, which means that all
         * objects are guaranteed to be expired within 1000 milliseconds of their
         * maximum lifetime.
         *
         * @param maxLifetime the maximum amount of time objects can exist in
         *    cache before being deleted.
         */
        public Cache(long maxLifetime) {
            this();
            this.maxLifetime = maxLifetime;
        }    /**
         * Create a new cache and specify the maximum size of for the cache in
         * bytes, and the maximum lifetime of objects.
         *
         * @param maxSize the maximum size of the cache in bytes.
         * @param maxLifetime the maximum amount of time objects can exist in
         *    cache before being deleted.
         */
        public Cache(int maxSize, long maxLifetime) {
            this();
            this.maxSize = maxSize;
            this.maxLifetime = maxLifetime;
        }    /**
         * Returns the current size of the cache in bytes.
         *
         * @return the size of the cache in bytes.
         */
        public int getSize() {
            return size;
        }    /**
         * Returns the maximum size of the cache in bytes. If the cache grows too
         * large, the least frequently used items will automatically be deleted so
         * that the cache size doesn't exceed the maximum.
         *
         * @return the maximum size of the cache in bytes.
         */
        public int getMaxSize() {
            return maxSize;
        }    /**
         * Sets the maximum size of the cache in bytes. If the cache grows too
         * large, the least frequently used items will automatically be deleted so
         * that the cache size doesn't exceed the maximum.
         *
         * @param maxSize the maximum size of the cache in bytes.
         */
        public void setMaxSize(int maxSize) {
            this.maxSize = maxSize;
            // It's possible that the new max size is smaller than our current cache
            // size. If so, we need to delete infrequently used items.
            cullCache();
        }    
      

  2.   

    /**还有接上面的
         * Returns the number of objects in the cache.
         *
         * @return the number of objects in the cache.
         */
        public synchronized int getNumElements() {
            return cachedObjectsHash.size();
        }    /**
         * Adds a new Cacheable object to the cache. The key must be unique.
         *
         * @param key a unique key for the object being put into cache.
         * @param object the Cacheable object to put into cache.
         */
        @SuppressWarnings("unchecked")
    public synchronized void add(Object key, Cacheable object) {
            // Delete an old entry if it exists.
            remove(key);        int objectSize = object.getSize();
            // If the object is bigger than the entire cache, simply don't add it.
            if (objectSize > maxSize * .90) {
                return;
            }
            size += objectSize;
            CacheObject cacheObject = new CacheObject(object, objectSize);
            cachedObjectsHash.put(key, cacheObject);
            // Make an entry into the cache order list.
            LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);
            // Store the cache order list entry so that we can get back to it
            // during later lookups.
            cacheObject.lastAccessedListNode = lastAccessedNode;
            // Add the object to the age list
            LinkedListNode ageNode = ageList.addFirst(key);
            // We make an explicit call to currentTimeMillis() so that total accuracy
            // of lifetime calculations is better than one second.
            ageNode.timestamp = System.currentTimeMillis();
            cacheObject.ageListNode = ageNode;        // If cache is too full, remove least used cache entries until it is
            // not too full.
            cullCache();
        }    /**
         * Gets an object from cache. This method will return null under two
         * conditions:<ul>
         *    <li>The object referenced by the key was never added to cache.
         *    <li>The object referenced by the key has expired from cache.</ul>
         *
         * @param key the unique key of the object to get.
         * @return the Cacheable object corresponding to unique key.
         */
        public synchronized Cacheable get(Object key) {
            // First, clear all entries that have been in cache longer than the
            // maximum defined age.
            deleteExpiredEntries();        CacheObject cacheObject = (CacheObject)cachedObjectsHash.get(key);
            if (cacheObject == null) {
                // The object didn't exist in cache, so increment cache misses.
                cacheMisses++;
                return null;
            }        // The object exists in cache, so increment cache hits.
            cacheHits++;        // Remove the object from it's current place in the cache order list,
            // and re-insert it at the front of the list.
            cacheObject.lastAccessedListNode.remove();
            lastAccessedList.addFirst(cacheObject.lastAccessedListNode);        return cacheObject.object;
        }    /**
         * Removes an object from cache.
         *
         * @param key the unique key of the object to remove.
         */
        public synchronized void remove(Object key) {
            CacheObject cacheObject = (CacheObject)cachedObjectsHash.get(key);
            // If the object is not in cache, stop trying to remove it.
            if (cacheObject == null) {
                return;
            }
            // remove from the hash map
            cachedObjectsHash.remove(key);
            // remove from the cache order list
            cacheObject.lastAccessedListNode.remove();
            cacheObject.ageListNode.remove();
            // remove references to linked list nodes
            cacheObject.ageListNode = null;
            cacheObject.lastAccessedListNode = null;
            // removed the object, so subtract its size from the total.
            size -= cacheObject.size;
        }    /**
         * Clears the cache of all objects. The size of the cache is reset to 0.
         */
        public synchronized void clear() {
            Object [] keys = cachedObjectsHash.keySet().toArray();
            for (int i=0; i<keys.length; i++) {
                remove(keys[i]);
            }        // Now, reset all containers.
            cachedObjectsHash.clear();
            cachedObjectsHash = new HashMap(103);
            lastAccessedList.clear();
            lastAccessedList = new LinkedList();
            ageList.clear();
            ageList = new LinkedList();        size = 0;
            cacheHits = 0;
            cacheMisses = 0;
        }    /**
         * Returns an array of the keys contained in the cache.
         *
         * @return an array of the keys present in the cache.
         */
        public Object [] keys() {
            return cachedObjectsHash.keySet().toArray();//提示这里出错了
        }    
      

  3.   

    Iterator在执行某些方法前会检测Collection内容是否变化,如果改变了就会抛出ConcurrentModificationException
    通过Iterator.remove()替代HashMap.remove()来删除集合内容,就不会出现此问题。
      

  4.   

    记得是同步方法中的内容修改时就会throw ConcurrentModificationException