带有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
只要您不介意在循环过程中项目从
映射中消失即可。完美我想不出如何使函数在没有找到它的情况下进行编译:映射
必需:映射