Atomically incrementing counters stored in ConcurrentHashMap

前端 未结 6 1460
猫巷女王i
猫巷女王i 2020-12-05 04:02

I would like to collect some metrics from various places in a web app. To keep it simple, all these will be counters and therefore the only modifier operation is to incremen

6条回答
  •  一生所求
    2020-12-05 04:55

    Got a necessity to do the same. I'm using ConcurrentHashMap + AtomicInteger. Also, ReentrantRW Lock was introduced for atomic flush(very similar behavior).

    Tested with 10 Keys and 10 Threads per each Key. Nothing was lost. I just haven't tried several flushing threads yet, but hope it will work.

    Massive singleusermode flush is torturing me... I want to remove RWLock and break down flushing into small pieces. Tomorrow.

    private ConcurrentHashMap counters = new ConcurrentHashMap();
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();
    
    public void count(String invoker) {
    
        rwLock.readLock().lock();
    
        try{
            AtomicInteger currentValue = counters.get(invoker);
            // if entry is absent - initialize it. If other thread has added value before - we will yield and not replace existing value
            if(currentValue == null){
                // value we want to init with
                AtomicInteger newValue = new AtomicInteger(0);
                // try to put and get old
                AtomicInteger oldValue = counters.putIfAbsent(invoker, newValue);
                // if old value not null - our insertion failed, lets use old value as it's in the map
                // if old value is null - our value was inserted - lets use it
                currentValue = oldValue != null ? oldValue : newValue;
            }
    
            // counter +1
            currentValue.incrementAndGet();
        }finally {
            rwLock.readLock().unlock();
        }
    
    }
    
    /**
     * @return Map with counting results
     */
    public Map getCount() {
        // stop all updates (readlocks)
        rwLock.writeLock().lock();
        try{
            HashMap resultMap = new HashMap();
            // read all Integers to a new map
            for(Map.Entry entry: counters.entrySet()){
                resultMap.put(entry.getKey(), entry.getValue().intValue());
            }
            // reset ConcurrentMap
            counters.clear();
            return resultMap;
    
        }finally {
            rwLock.writeLock().unlock();
        }
    
    }
    

提交回复
热议问题