Java ConcurrentHashMap 不是线程安全的..呢? [英] Java ConcurrentHashMap not thread safe.. wth?

查看:59
本文介绍了Java ConcurrentHashMap 不是线程安全的..呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以前用过 HashMap

I was using HashMap before like

   public Map<SocketChannel, UserProfile> clients = new HashMap<SocketChannel, UserProfile>();

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

now I've switched to ConcurrentHashMap to avoid synchronized blocks and now i'm experiencing problems my server is heavily loaded with 200-400 concurrent clients every second which is expected to grow over time.

现在看起来像这样

public ConcurrentHashMap<SocketChannel, UserProfile> clients = new ConcurrentHashMap<SocketChannel, UserProfile>();

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

My server design works like this. I have a worker thread(s) for processing huge amounts of packets. Each packet is checked with a packetHandler sub-routine (not part of thread) pretty much any client can call it at anytime it's almost like static but it isn't.

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

My whole server is mostly single threaded except for the packet processing portion.

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

Anyways so when someone uses a command like count up all clients online and get some information from them.

客户端也有可能在计数过程中断开连接并从 ConcurrentHashMap 中删除(这会导致我的问题).

It is also possible that clients can get disconnected and removed from ConcurrentHashMap while the counting is in progress (which causes my problems).

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

Also I'd like to add some code here.

                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++;
                        }
                    }
                }

我的意思是,我当然会通过在迭代器中添加一个 try-catch 异常来跳过这些空客户端来修复它.

I mean of course i'm going to fix it by adding a try-catch Exception inside the Iterator to skip these null clients.

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

But what I don't understand if it checks above if(person != null) shouldn't the code nested automatically works..

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

if it doesn't means it got removed while it was iterating which should be impossible since it's thread safe wtf?

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

What should I do? or is try-catch Exception the best way?

这是个例外

java.lang.NullPointerException
    at Server.processPackets(Server.java:398)
    at PacketWorker.run(PacketWorker.java:43)
    at java.lang.Thread.run(Thread.java:636)

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

The processPackets contains the code above. and the comment indicates the line count #

谢谢你对我的启发.

推荐答案

您需要阅读 ConcurrentHashMap.values() 方法,特别注意这个描述如何为values() 集合工作:

You need to read the javadocs for the ConcurrentHashMap.values() method, paying special attention to this description of how the iterator for the values() collection works:

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

"The view's iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction."

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

The iterator does not give you a consistent snapshot of the state of the values collection, but it is thread-safe, and the expected range of behaviours is clearly specified.

如果您想要一个 Map 实现,它为您提供地图中值(或键或条目)的一致快照,并允许您在修改的同时进行迭代,您可能需要创建一个自定义 Map 包装类(即以原子方式复制集合)...或成熟的自定义 Map 实现.对于您的用例,两者都可能比 ConcurrentHashMap 慢很多.

If you want a Map implementation that gives you a consistent snapshot of the values (or keys, or entries) in the map AND allows you to iterate concurrently with modifications, you will probably need to create a custom Map wrapper class (that copies the collections atomically) ... or a full-blown custom Map implementation. Both are likely to be a lot slower than a ConcurrentHashMap for your use-case.

这篇关于Java ConcurrentHashMap 不是线程安全的..呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆