[英]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.