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)
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)
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();
}
* 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();//提示这里出错了
}
通过Iterator.remove()替代HashMap.remove()来删除集合内容,就不会出现此问题。