ConcurrentHashMap cas操作以及AtomicLongMap类
假設有一個需求:實時統計某個網址的訪問次數
方案一:利用concurrentHashMap,進行統計
private Map<String, Long> wordCounts = new ConcurrentHashMap<>();public long increase(String word) {Long oldValue = wordCounts.get(word);Long newValue = (oldValue == null) ? 1L : oldValue + 1;wordCounts.put(word, newValue);return newValue; }在多個線程環境increase()的統計是錯誤的,因為多個線程用相同的word調用時,很可能會覆蓋相互的結果,造成記錄的次數比實際出現的次數少。concurrentHashMap 能保證的是每一個操作(put,get,delete…)本身是線程安全的,但是increase是先取、再加多個步驟。
對上面increase方法加鎖可以解決問題,但是會降低并發量。
方案二:借助ConcurrentMap接口定義了幾個基于 CAS 操作:
private ConcurrentMap<String, Long> wordCounts = new ConcurrentHashMap<>();public long increase(String word) {Long oldValue, newValue;while (true) {oldValue = wordCounts.get(word);if (oldValue == null) {// Add the word firstly, initial the value as 1newValue = 1L;if (wordCounts.putIfAbsent(word, newValue) == null) {break;}} else {newValue = oldValue + 1;if (wordCounts.replace(word, oldValue, newValue)) {break;}}}return newValue; }該方法有點復雜,主要因為ConcurrentMap中不能保存value為null的值,所以得同時處理word不存在和已存在兩種情況。此外,這里介紹一下ConcurrentHashMap中的常用cas方法(原子操作):
1)putIfAbsent(k,v):
- k不存在:插入,返回null;
- 否則(k存在):返回原值
2)replace(k,v1,v2):
- k存在 && 原值等于v1,則更新v1為v2,返回true;
- 否則,返回false;
方案三:使用ConcurrentHashMap和AtomicLong:
private final ConcurrentMap<String, AtomicLong> wordCounts = new ConcurrentHashMap<>();public long increase(String word) {AtomicLong number = wordCounts.get(word);if (number == null) {AtomicLong newNumber = new AtomicLong(0);number = wordCounts.putIfAbsent(word, newNumber);if (number == null) {number = newNumber;}}return number.incrementAndGet(); }這個實現仍然有一處需要說明的地方,如果多個線程同時增加一個目前還不存在的詞,那么很可能會產生多個newNumber對象,但最終只有一個newNumber有用,其他的都會被扔掉。對于這個應用,這不算問題,創建AtomicLong的成本不高,而且只在添加不存在詞是出現。但是對于緩存場景(緩存創建成本高),就有些問題了。
方案四:使用AtomicLongMap:
AtomicLongMap是Google Guava項目的一個類,它是線程安全、支持并發訪問的。對于計數推薦使用該類。
private AtomicLongMap<String> urlCoutn = AtomicLongMap.create();public long increase(String url) {long newValue = urlCoutn.incrementAndGet(url);return newValue;}public Long getCount(String url) {return urlCoutn.get(url);}參考
https://blog.csdn.net/HEYUTAO007/article/details/61429454
https://blog.csdn.net/u011983531/article/details/65936945
總結
以上是生活随笔為你收集整理的ConcurrentHashMap cas操作以及AtomicLongMap类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OSChina 周一乱弹 —— 中年少女
- 下一篇: 埃及分数 (迭代加深入门)