ex:并发编程经(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tonghuawanli/article/details/83051521

CAS实际使用

ConcurrentHashMap是支持并发的,但是如下代码有啥问题?

private final Map<String, RateLimiter> limiterMap = new ConcurrentHashMap<>();
// 并发使用的方法
public void someMethod(){
		if (!limiterMap.containsKey(limitName)) {
            rateLimiter = RateLimiter.create(rateLimiterAnno.limitCount());
            limiterMap.put(limitName, rateLimiter);
        }
        LOG.info("-----------"+limiterMap.get(limitName).hashCode());
        rateLimiter = limiterMap.get(limitName);
}

如上代码从limiterMap获取到的rateLimiter在并发环境下可能并不是同一个,concurrentHashMap能保证的是每一个操作(put,get,delete…)本身是线程安全的,但是someMethod对concurrentHashMap的操作是一个组合,先get(containsKey)再put,所以多个线程的操作出现了覆盖。

那么如何防止put覆盖呢?可参考:http://www.importnew.com/26035.html
用到了CAS思想,CAS操作putIfAbsent,参考地址里用的是统计接口访问次数,即Map存储<String,Long>.
本问题解决代码:

private final Map<String, RateLimiter> limiterMap = new ConcurrentHashMap<>();
private RateLimiter rateLimiter;

if (!limiterMap.containsKey(limitName)) {
    rateLimiter = RateLimiter.create(rateLimiterAnno.limitCount());
}
// 自定义方法
rateLimiter = getRateLimiter(limitName, rateLimiter);

// 解决多线程下:先get再put,多个线程的操作出现覆盖
    private RateLimiter getRateLimiter(String key, RateLimiter rateLimiter) {
        while (true) {
            // 其他线程添加到了Map
            if (limiterMap.get(key) != null) {
                break;
            } else {
                // 添加RateLimiter到Map成功,退出循环
                if (limiterMap.putIfAbsent(key, rateLimiter) == null) {
                    break;
                }
            }
        }
        return limiterMap.get(key);
    }

猜你喜欢

转载自blog.csdn.net/tonghuawanli/article/details/83051521
ex1
今日推荐