0

我有一个用户列表,每个用户都有一系列他访问过的地方(例如列表 = 1,2,3,1,2,8,10,1...usw.)。现在我想弄清楚每个地方的访问频率。此外,我真的很想为此采取 fork/join 。现在我的实际问题是,您知道在这里使用 concurrentHashMap 的方法吗,因为当前的问题是在

map.put(i, map.get(i)+1);// lost updates here

你有一个好主意来解决这个问题而不锁定整个地图(地图的某些部分是否有部分锁定,就像 put() 一样?)。我知道,我可以为每个用户创建一张地图,然后再次加入他们,但我想,也许有人有更好的解决方案。

public class ForkUsers extends RecursiveAction{

    ArrayList<User>users;
    ConcurrentHashMap<Integer,Integer>map;
    int indexfrom;
    int indexto;
    ForkUsers(ArrayList<User>users,ConcurrentHashMap<Integer,Integer> map,int indexfrom,int indexto){
        this.users=users;
        this.map=map;
        this.indexfrom=indexfrom;
        this.indexto=indexto;
    }


    void computeDirectly(User user){
        for(Integer i:user.getVisitedPlaces()){
            if(map.get(i)==null){
                map.putIfAbsent(i, 1);
            }else{
                map.put(i, map.get(i)+1);// lost updates here 
            }

        }

    }

    protected void compute() {

        if(indexfrom==indexto){
            computeDirectly(users.get(indexfrom));
        }else{
            int half=(indexfrom+indexto)/2;
            invokeAll(new ForkUsers(users,map,indexfrom,half),new ForkUsers(users,map,half+1,indexto));
        }

    }
}
4

1 回答 1

1

即使您使用的是ConcurrentHashMap,也不会阻止读取-更新-写入竞争条件;两个线程都调用get,然后都加 1,然后两个put值都只返回一个更新。您可以同步整个读取-更新-写入操作,或者(我的偏好)使用 anAtomicInteger作为值并incrementAndGet改为使用。

于 2013-08-25T10:25:06.107 回答