簡體   English   中英

Java ConcurrentHashMap不是線程安全的..是嗎?

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

之前我正在使用HashMap

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

現在我已經切換到ConcurrentHashMap以避免同步塊,現在我遇到了問題,我的服務器每秒都有200-400個並發客戶端,預計會隨着時間的推移而增長。

現在看起來像這樣

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

我的服務器設計就像這樣。 我有一個工作線程來處理大量的數據包。 每個數據包都使用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++;
                        }
                    }
                }

我的意思是我當然要通過在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)

processPackets包含上面的代碼。 並且注釋表示行數#

謝謝你的啟發。

您需要讀取ConcurrentHashMap.values()方法的javadoc,特別注意values()集合的迭代器如何工作的描述:

“視圖的迭代器是一個”弱一致“的迭代器,它永遠不會拋出ConcurrentModificationException,並保證遍歷構造迭代器時存在的元素,並且可能(但不保證)反映構造之后的任何修改。

迭代器不會為您提供值集合狀態的一致快照,但它是線程安全的 ,並且明確指定了預期的行為范圍。

如果您希望Map實現為您提供映射中值(或鍵或條目)的一致快照,並允許您同時進行修改,則可能需要創建自定義Map包裝類(復制集合)原子地...或者是一個完整的自定義Map實現。 對於您的用例,兩者都可能比ConcurrentHashMap慢很多。

java.util.concurrent.ConcurrentHashMap中不允許空值。 因此,代碼中的null check(person!= null)是不必要的。

如果要在迭代時拒絕修改Map,則必須在上面的代碼和所有修改操作代碼中使用同步塊。

您可能會發現在迭代它時不能修改地圖。 如果是這種情況,您可能希望在單獨的集合中獲取值和鍵並迭代它,因為它將是不可變的。

它不是完美的,但另一個選擇是擴展ConcurrentHashMap ,當添加或刪除某些內容時,您更新這四個變量,因此您不必每次都遍歷整個列表,因為這似乎是浪費cpu周期。

以下是一些可能有用的鏈接:

這個講述了一個事實,即改進的並發性是因為放松了一些承諾。 http://www.ibm.com/developerworks/java/library/j-jtp07233.html

內存一致性屬性解釋: http//download-llnw.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

我沒看到你的代碼有什么問題。 因為崩潰實際上不太可能發生在else ,所以getGender()方法可能返回null

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM