1. 程式人生 > >ConcurrentHashMap統計單詞出現的次數

ConcurrentHashMap統計單詞出現的次數

/**
 * 統計單詞出現的次數
 * @author wucj
 * @date 2019-06-27 11:35
 **/
public class WordsCount {

    private final HashMap<String,Long> wordCountHashMap = new HashMap<>();

    private final ConcurrentHashMap<String,Long> wordCountConcurrentHashMap = new ConcurrentHashMap<>();

    private final ConcurrentHashMap<String,AtomicLong> wordCountAtomicConcurrentHashMap = new ConcurrentHashMap<>();


    /**
     * 多執行緒併發時會出現錯誤覆蓋
     * @param word
     * @return
     */
    public long increaseHm(String word){
        Long oldCount = wordCountHashMap.get(word);
        long newCount = null==oldCount?0:oldCount+1;
        wordCountHashMap.put(word,newCount);
        return newCount;
    }

    /**
     * 執行效率可能偏低、佔用cpu過多
     * @param word
     * @return
     */
    public long increaseCasChm(String word){
        Long oldValue;
        long newValue = 0;
        // 空轉也是很耗時的
        while (true){
            oldValue = wordCountConcurrentHashMap.get(word);
            if(null==oldValue){
                newValue = 1;
                // 如果map中不存在值,則設定當前值,並且返回null
                // 如果map中存在值,則不設定當前值,並且返回原始值
                if(wordCountConcurrentHashMap.putIfAbsent(word,newValue)==null){
                    break;
                }
            }else{
                newValue = oldValue +1;

                if(wordCountConcurrentHashMap.replace(word,oldValue,newValue)){
                    break;
                }
            }
        }
        return newValue;
    }

    /**
     * 原子操作:上面的實現每次呼叫都會涉及Long物件的拆箱和裝箱操作,很明顯,更好的實現方式是採用AtomicLong
     * 缺點:如果多個執行緒同時增加一個目前還不存在的詞,那麼很可能會產生多個newNumber物件,
     * 但最終只有一個newNumber有用,其他的都會被扔掉。對於這個應用,這不算問題,建立AtomicLong的成本不高,而且只在新增不存在詞是出現。
     * @param word
     * @return
     */
    public long increaseAtomicLong(String word){
        AtomicLong number = wordCountAtomicConcurrentHashMap.get(word);
        if(number==null){
           AtomicLong newAtomicLong = new AtomicLong(0);
           number = wordCountAtomicConcurrentHashMap.putIfAbsent(word,newAtomicLong);
           if(null==number){
               number = newAtomicLong;
           }
        }
        return number.incrementAndG