带有RemoveedStantry的Java LinkedHashMap导致Java.lang.NullPointerException
错误如下所示带有RemoveedStantry的Java LinkedHashMap导致Java.lang.NullPointerException,java,map,get,linkedhashmap,lru,Java,Map,Get,Linkedhashmap,Lru,错误如下所示 Exception in thread "Thread-1" java.lang.NullPointerException at java.util.LinkedHashMap$Entry.remove(LinkedHashMap.java:332) at java.util.LinkedHashMap$Entry.recordAccess(LinkedHashMap.java:356) at java.util.LinkedHashMap.get(Link
Exception in thread "Thread-1" java.lang.NullPointerException
at java.util.LinkedHashMap$Entry.remove(LinkedHashMap.java:332)
at java.util.LinkedHashMap$Entry.recordAccess(LinkedHashMap.java:356)
at java.util.LinkedHashMap.get(LinkedHashMap.java:304)
at Server.getLastFinishedCommands(Server.java:9086)
at Server.processPacket(Server.java:484)
at PacketWorker.run(PacketWorker.java:34)
at java.lang.Thread.run(Thread.java:744)
public static int final MAX_COMMANDS_QUEUE = 5000;
public Map<Long, CCommand> finishedCommands = createLRUMap(MAX_COMMANDS_QUEUE);
在我使用的GetLastFinishedCommand
中
public List<CCommand> getLastFinishedCommands(UserProfile player) {
List<CCommand> returnList = new ArrayList<CCommand>();
if(!finishedCommands.containsKey(player.myWebsitecmd-1)) {
getSavedState(player);
return null;
}
try { //<-- added this try/catch so it doesn't happen again.
//Get commands.
CCommand cmd;
long i;
long startIndex = player.myWebsitecmd;
long endIndex = startIndex+LIMIT_COMMANDS;
for(i = startIndex; i <= endIndex; i++) {
cmd = finishedCommands.get(i); //<-- this is line 9086
if(cmd == null) {
return returnList;
}
returnList.add(cmd);
}
} catch(Exception e) {} //<-- added this try/catch so it doesn't happen again.
return returnList;
}
公共列表GetLastFinishedCommand(用户配置文件播放器){
List returnList=new ArrayList();
如果(!finishedCommands.containsKey(player.myWebsitecmd-1)){
getSavedState(播放器);
返回null;
}
尝试{//maxEntries;
}
};
}
像这样使用它
Exception in thread "Thread-1" java.lang.NullPointerException
at java.util.LinkedHashMap$Entry.remove(LinkedHashMap.java:332)
at java.util.LinkedHashMap$Entry.recordAccess(LinkedHashMap.java:356)
at java.util.LinkedHashMap.get(LinkedHashMap.java:304)
at Server.getLastFinishedCommands(Server.java:9086)
at Server.processPacket(Server.java:484)
at PacketWorker.run(PacketWorker.java:34)
at java.lang.Thread.run(Thread.java:744)
public static int final MAX_COMMANDS_QUEUE = 5000;
public Map<Long, CCommand> finishedCommands = createLRUMap(MAX_COMMANDS_QUEUE);
public static int final MAX\u COMMANDS\u QUEUE=5000;
publicmap finishedCommands=createLRUMap(最大命令队列);
很明显,这是一种在与多个线程一起使用时发生的CocurrentModificationException。。但是为什么它会在内部崩溃,有人知道我如何使用它,比如一个CocurrentHashMap吗?我试图解决这个问题,而不是仅仅在整个getLastFinishedCommands
函数中添加try/catch
我想要一个从旧垃圾中清除自己但仍保留至少5000个键/值项的映射。基于stacktrace,我假设代码试图从另一个线程已删除其项的索引中删除值。这使得它在访问
null
引用的属性时抛出NPE
。也许,您应该尝试同步集合
从LinkedHashMap
请注意,此实现是不同步的。如果多个线程同时访问链接的哈希映射,并且至少有一个线程在结构上修改映射,则必须在外部对其进行同步。这通常是通过在自然封装贴图的某个对象上进行同步来实现的。如果不存在此类对象,则应使用Collections.synchronizedMap方法“包装”映射。最好在创建时执行此操作,以防止意外不同步地访问映射:
您说过有多个线程正在访问此地图。这确实可能会导致NPE在
LinkedHashMap.Entry
实例的remove
操作中出现。这是此方法的实现:
private void remove() {
before.after = after;
after.before = before;
}
此处的前和后指的是当前条目链接的前置项和后续项。如果另一个线程已经更改了条目之间的链接,这当然会导致意外的行为,例如NPE
解决方案是——您猜对了——将生成的地图包装在同步地图中。例如:
public static <K, V> Map<K, V> createLRUMap(final int maxEntries) {
Map<K,V> result = new LinkedHashMap<K, V>(maxEntries*3/2, 0.7f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxEntries;
}
};
return Collections.synchronizedMap(result);
}
public静态映射createLRUMap(final int maxEntries){
映射结果=新LinkedHashMap(maxEntries*3/2,0.7f,真){
@凌驾
受保护的布尔重构(Map.Entry最早){
返回size()>maxEntries;
}
};
返回集合。同步映射(结果);
}
此同步包装器确实会同步对基础映射的所有调用,因此每个方法(如get、put、contains、size等)只允许一个线程执行。永远不要使用空catch块。这就是地狱之路。作为一个临时解决方案,我放了一个try/catch
,希望它现在能工作,仍然在寻找如何在不添加外部类或库的情况下以正确的方式修复它。我认为您的代码是正确的。我只是看看我的实现,它是一样的。这可能是JDK中的bug吗?请删除空的try-catch
块。这不是来源的一部分,有这个问题和混乱的事情。你能发布java-version
吗?我能用集合来包装地图吗?同步地图
还是会引起同样的问题?像这样publicmap finishedCommands=Collections.synchronizedMap(createLRUMap(MAX_COMMANDS_QUEUE))代码>是的,你可以很好地使用它。试试看!这应该可以解决这个问题,因为返回一个由指定映射支持的同步(线程安全)映射。为了保证串行访问,必须通过返回的映射来完成对备份映射的所有访问
@SSpoke您是说您正在并发环境中使用映射
Collections.synchronizedMap
非常粗糙,可能无法工作-如果同时使用此Map
,您需要非常小心,充分了解和应对危险。FinishedCommand
每10毫秒由一个线程生成,当用户连接到网站时,它会请求finishedCommands
在某个范围内可以是Long
的任何范围,而且该范围不应跳过任何范围。如果跳过,则应立即返回。如果它没有得到任何东西,它只会第二次请求它,我想下次应该得到它?但是是的。。我不想减慢将命令放入finishedcommands
Map的过程。@SSpoke您可能可以,看看您的代码,使用集合解决此问题。synchronizedMap
只要您不介意在循环过程中项目从映射中消失即可。完美我想不出如何使函数在没有找到它的情况下进行编译:映射
必需:映射