/** * 统计单词出现的次数 * @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.incrementAndGet(); } }