带有removeEldestEntry的Java LinkedHashMap导致java.lang.NullPointerException [英] Java LinkedHashMap with removeEldestEntry causes java.lang.NullPointerException
问题描述
错误看起来像这样
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)
里面 getLastFinishedCommands
我使用
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;
}
我想制作一个自动删除旧条目的地图,所以我使用这个代码段
I wanted to make a Map that auto removes old entries so I used this snippet
public static <K, V> Map<K, V> createLRUMap(final int maxEntries) {
return new LinkedHashMap<K, V>(maxEntries*3/2, 0.7f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxEntries;
}
};
}
使用它像这样
public static int final MAX_COMMANDS_QUEUE = 5000;
public Map<Long, CCommand> finishedCommands = createLRUMap(MAX_COMMANDS_QUEUE);
显然,它是某种CocurrentModifcationException,当使用多个线程时会发生,但为什么它会在内部崩溃任何人都知道我可以像CocurrentHashMap一样使用它吗?我正在尝试解决这个问题,而不用仅仅在整个 getLastFinishedCommands
函数中放置一个try / catch。
Obviously it's some kind of CocurrentModifcationException which happens when using with multiple threads.. but why does it crash internally, anyone know how I can use this with like a CocurrentHashMap? I'm trying to fix this without resorting to just putting a try/catch around the whole getLastFinishedCommands
function.
我想要一个从旧垃圾中清除的地图,但仍保留至少5000个键/值条目。
I want a Map that clears itself from old junk but still holds atleast 5000 key/value entries.
推荐答案
你说多个线程正在访问此地图。这实际上可以导致删除 c $ c> LinkedHashMap.Entry
实例中的NPE。这是这种方法的实现:
You said that multiple threads are accessing this map. This could indeed cause the NPE in the remove
operation of a LinkedHashMap.Entry
instance. This is the implementation of this method:
private void remove() {
before.after = after;
after.before = before;
}
这里之前
和之后将
引用到当前条目的链接前代和后继。如果另一个线程已经更改了条目之间的链接,这当然可能会导致意外的行为,例如NPE。
Here before
and after refer
to the linked predecessor and successor of the current entry. If another thread already changed the linking between the entries, this could of course result in an unexpected behavior, such as the NPE.
解决方案是 - 你猜对了 - 将生成的地图包装在同步的地图中。例如:
The solution is - you guessed correctly - to wrap your produced map in a synchronized map. Such as:
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);
}
这个同步包装器确实将所有调用同步到底层地图,所以只有一个单线程允许通过每种方法(如get,put,contains,size等)。
This synchronized wrapper will indeed synchronize all calls to the underlying map, so only one single thread is allowed to go through each method (such as get, put, contains, size, and so on).
这篇关于带有removeEldestEntry的Java LinkedHashMap导致java.lang.NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!