Java ConcurrentHashMap不是线程安全的..是吗?

SSp*_*oke 8 java null try-catch nullpointerexception concurrenthashmap

之前我正在使用HashMap

   public Map<SocketChannel, UserProfile> clients = new HashMap<SocketChannel, UserProfile>();
Run Code Online (Sandbox Code Playgroud)

现在我已经切换到ConcurrentHashMap以避免同步块,现在我遇到了问题,我的服务器每秒都有200-400个并发客户端,预计会随着时间的推移而增长.

现在看起来像这样

public ConcurrentHashMap<SocketChannel, UserProfile> clients = new ConcurrentHashMap<SocketChannel, UserProfile>();
Run Code Online (Sandbox Code Playgroud)

我的服务器设计就像这样.我有一个工作线程来处理大量的数据包.每个数据包都使用packetHandler子程序(不是线程的一部分)进行检查,几乎任何客户端都可以随时调用它,它几乎就像静态但不是.

我的整个服务器大多是单线程的,除了数据包处理部分.

无论如何,当有人使用命令时,如在线计算所有客户端并从中获取一些信息.

当计数正在进行时(这会导致我的问题),客户端也可能会断开连接并从ConcurrentHashMap中删除.

另外我想在这里添加一些代码.

                int txtGirls=0;
                int vidGirls=0;
                int txtBoys=0;
                int vidBoys=0;
                Iterator i = clients.values().iterator();
                while (i.hasNext()) {
                    UserProfile person = (UserProfile)i.next();
                    if(person != null) {
                        if(person.getChatType()) {
                            if(person.getGender().equals("m"))
                                vidBoys++;
                            else //<-- crash occurs here.
                                vidGirls++;
                        } else if(!person.getChatType()) {
                            if(person.getGender().equals("m"))
                                txtBoys++;
                            else
                                txtGirls++;
                        }
                    }
                }
Run Code Online (Sandbox Code Playgroud)

我的意思是我当然要通过在Iterator中添加一个try-catch Exception来跳过这些空客户端来修复它.

但我不明白,如果检查上面是否(人!= null)不应该嵌套的代码自动工作..

如果它不意味着它在迭代时被删除,这应该是不可能的,因为它是线程安全的wtf?

我该怎么办?或者是try-catch Exception最好的方法?

这是例外

java.lang.NullPointerException
    at Server.processPackets(Server.java:398)
    at PacketWorker.run(PacketWorker.java:43)
    at java.lang.Thread.run(Thread.java:636)
Run Code Online (Sandbox Code Playgroud)

processPackets包含上面的代码.并且注释表示行数#

谢谢你的启发.

Ste*_*n C 16

你需要阅读的javadoc的ConcurrentHashMap.values()方法,特别注意为迭代器是如何描述values()的收集工作:

"视图的迭代器是一个"弱一致"的迭代器,它永远不会抛出ConcurrentModificationException,并保证遍历构造迭代器时存在的元素,并且可能(但不保证)反映构造之后的任何修改.

迭代器不会为您提供值集合状态的一致快照,但它是线程安全的,并且明确指定了预期的行为范围.

如果您希望Map实现为您提供映射中值(或键或条目)的一致快照,并允许您同时进行修改,则可能需要创建自定义Map包装类(复制集合)原子地...或者是一个完整的自定义Map实现.对于您的用例,两者都可能比ConcurrentHashMap慢很多.

  • @SSpoke - 如果NPE恰好发生在你指出的点上,那可能不是因为迭代器返回的`null`.更有可能的是,'person.getGender()`返回了`null`. (3认同)