简体   繁体   English

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

[英]Java ConcurrentHashMap not thread safe.. wth?

I was using HashMap before like 之前我正在使用HashMap

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

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

which now looks like this 现在看起来像这样

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

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. 每个数据包都使用packetHandler子程序(不是线程的一部分)进行检查,几乎任何客户端都可以随时调用它,它几乎就像静态但不是。

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. 无论如何,当有人使用命令时,如在线计算所有客户端并从中获取一些信息。

It is also possible that clients can get disconnected and removed from ConcurrentHashMap while the counting is in progress (which causes my problems). 当计数正在进行时(这会导致我的问题),客户端也可能会断开连接并从ConcurrentHashMap中删除。

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

I mean of course i'm going to fix it by adding a try-catch Exception inside the Iterator to skip these null clients. 我的意思是我当然要通过在Iterator中添加一个try-catch Exception来跳过这些空客户端来修复它。

But what I don't understand if it checks above if(person != null) shouldn't the code nested automatically works.. 但我不明白,如果检查上面是否(人!= null)不应该嵌套的代码自动工作..

if it doesn't means it got removed while it was iterating which should be impossible since it's thread safe wtf? 如果它不意味着它在迭代时被删除,这应该是不可能的,因为它是线程安全的wtf?

What should I do? 我该怎么办? or is try-catch Exception the best way? 或者是try-catch Exception最好的方法?

Here is the exception 这是例外

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

The processPackets contains the code above. processPackets包含上面的代码。 and the comment indicates the line count # 并且注释表示行数#

Thanks for enlightening me. 谢谢你的启发。

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: 您需要读取ConcurrentHashMap.values()方法的javadoc,特别注意values()集合的迭代器如何工作的描述:

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

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

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. 如果您希望Map实现为您提供映射中值(或键或条目)的一致快照,并允许您同时进行修改,则可能需要创建自定义Map包装类(复制集合)原子地...或者是一个完整的自定义Map实现。 Both are likely to be a lot slower than a ConcurrentHashMap for your use-case. 对于您的用例,两者都可能比ConcurrentHashMap慢很多。

java.util.concurrent.ConcurrentHashMap does not allow null value. java.util.concurrent.ConcurrentHashMap中不允许空值。 So, null check(person != null) in your code is unnecessary. 因此,代码中的null check(person!= null)是不必要的。

If you want to deny modification of Map while iteration, you must use synchronization block in above code and all modification operation codes. 如果要在迭代时拒绝修改Map,则必须在上面的代码和所有修改操作代码中使用同步块。

You may find that you can't have the map get modified while you are iterating through it. 您可能会发现在迭代它时不能修改地图。 If that is the case you may want to get the values and keys in a separate collection and iterate through that, as it will be immutable. 如果是这种情况,您可能希望在单独的集合中获取值和键并迭代它,因为它将是不可变的。

It won't be perfect, but the other option is to extend ConcurrentHashMap and when something is added or removed you update these four variables, so you don't have to iterate through the entire list each time, as that seems to be a waste of cpu cycles. 它不是完美的,但另一个选择是扩展ConcurrentHashMap ,当添加或删除某些内容时,您更新这四个变量,因此您不必每次都遍历整个列表,因为这似乎是浪费cpu周期。

Here are a couple of links that may be useful: 以下是一些可能有用的链接:

This one talks a bit about the fact that the improved concurrency is because of relaxing of some promises. 这个讲述了一个事实,即改进的并发性是因为放松了一些承诺。 http://www.ibm.com/developerworks/java/library/j-jtp07233.html http://www.ibm.com/developerworks/java/library/j-jtp07233.html

memory consistency properties explained: http://download-llnw.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility 内存一致性属性解释: http//download-llnw.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

I don't see anything wrong with your code. 我没看到你的代码有什么问题。 Because it's unlikely that the crash actually occurs at the else , it's likely that the getGender() method is returning null . 因为崩溃实际上不太可能发生在else ,所以getGender()方法可能返回null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM