java – 何时以及如何使用ConcurrentHashMap的其他同步?

我需要知道何时应该在使用ConcurrentHashMap时向我的代码添加一些同步块.假设我有一个类似的方法:

private static final ConcurrentMap<String, MyObjectWrapper> myObjectsCache = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY);

    public List<MyObject> aMethod(List<String> ids, boolean b) {
        List<MyObject> result = new ArrayList<>(ids.size());
        for (String id : ids) {
            if (id == null) {
                continue;
            }
            MyObjectWrapper myObjectWrapper = myObjectsCache.get(id);
            if (myObjectWrapper == null) {
                continue;
            }
            if (myObjectWrapper.getObject() instanceof MyObjectSub) {
                ((MyObjectSub) myObjectWrapper.getObject()).clearAField();
                myObjectWrapper.getObject().setTime(System.currentTimeMillis());
            }
            result.add(myObjectWrapper.getObject());
            if (b) {
                final MyObject obj = new MyObject(myObjectWrapper.getObject());
                addObjectToDb(obj);
            }
        }
        return result;
    }

我该如何有效地使这个方法并发?
我认为“get”是安全的但是一旦我从缓存中获取值并更新缓存对象的字段 – 可能会出现问题,因为另一个线程可以获得相同的包装并尝试更新相同的底层对象…我应该添加吗同步?如果是这样,那么我应该从“get”到循环迭代结束还是整个循环同步?

也许有人可以分享一些更具体的指导方针,当需要对循环内的地图键/值等进行更多操作时,正确有效地使用ConcurrentHashMap …

我真的很感激.

编辑:
该问题的一些背景:
我目前正致力于在生产代码中重构一些dao类,并且一些类使用HashMaps来缓存从数据库中检索的数据.使用缓存(用于写入或读取)的所有方法都将其整个内容放在同步(缓存)块中(播放安全吗?).我没有太多的并发经验,我真的想借此机会学习.我天真地将HashMaps更改为ConcurrentHashMaps,现在想要删除必要的同步bloocks.所有缓存都用于写入和读取.所提出的方法基于我已经改变的方法之一,现在我正在尝试学习何时以及在何种程度上同步.方法clearAField只更改包装的POJO对象的一个​​字段的值,addObjectToDb尝试将对象添加到数据库.

其他示例是重新填充缓存:

public void findAll() throws SQLException{
    // get data from database into a list
    List<Data> data=getAllDataFromDatabase();
    cacheCHM.clear();
    cacheCHM.putAll(data);
} 

在这种情况下,我应该将clear和putAll放在一个synchronize(cacheCHM)块中,对吗?

我试图找到并阅读一些关于CHM的正确和有效使用的帖子/文章,但大多数处理单个操作,没有循环等….我发现的最好的是:
http://www.javamadesoeasy.com/2015/04/concurrenthashmap-in-java.html

最佳答案 你没有提到你期望在你的应用程序中发生什么并发,所以我假设你有多个线程调用aMethod,没有别的.

你只需要一次调用ConcurrentHashMap:myObjectsCache.get(id),这很好.事实上,因为没有任何东西将数据写入你的objectCache [见上面的假设]你甚至不需要ConcurrentHashMap!你可以使用任何不可变的集合.你最后有一个可疑的行:addObjectToDb(obj),这个方法是否也会影响你的缓存?如果是这样它仍然是安全的(可能,我们必须看到方法是确定的),但你肯定需要ConcurentHashMap.

危险在于您更改对象的位置,此处:

myObjectWrapper.getObject().clearAField();
myObjectWrapper.getObject().setTime(System.currentTimeMillis());

多个线程可以同时在同一个对象上调用这些方法.不知道这些方法做了什么,我们不能说这是否安全.如果这些方法都标记为同步,或者您注意确保这些方法同时运行是安全的,那么您就可以了(但请注意,这些方法的范围可以按照您可能直观预期的不同顺序运行! ).如果您不那么小心,那么可能存在数据损坏.

点赞