Java 如何在ConcurrentHashMap中添加新成员<;字符串,列表<;字符串>&燃气轮机;没有同步或锁定

Java 如何在ConcurrentHashMap中添加新成员<;字符串,列表<;字符串>&燃气轮机;没有同步或锁定,java,Java,我读过这个问题。对于ConcurrentHashMap,多个线程将被设置为相同的列表。在值之前添加(值)执行,条目可能被删除,新成员添加失败。如何在ConcurrentHashMap中添加新成员,而不使用synchronized或lock private ConcurrentHashMap<String, List<String>> entries = new ConcurrentHashMap<String, Lis

我读过这个问题。对于
ConcurrentHashMap
,多个线程将被设置为相同的列表。在<代码>值之前添加(值)执行,条目可能被删除,新成员添加失败。如何在
ConcurrentHashMap
中添加新成员,而不使用
synchronized
lock

private ConcurrentHashMap<String, List<String>> entries =
                        new ConcurrentHashMap<String, List<String>>();

public void record(String key, String value) {
    List<String> values = entries.get(key);
    if (values == null) {
        values = Collections.synchronizedList(new ArrayList<String>());
        List<String> values2 = entries.putIfAbsent(key, values);
        if (values2 != null)
            values = values2;  
    }
    values.add(value); // entry may be removed here, and this member will lose.
}
私有ConcurrentHashMap条目=
新的ConcurrentHashMap();
公共无效记录(字符串键、字符串值){
列表值=条目.get(键);
如果(值==null){
values=Collections.synchronizedList(新的ArrayList());
列表值2=条目。putIfAbsent(键、值);
如果(值2!=null)
数值=数值2;
}
values.add(value);//可能会在此处删除条目,并且此成员将丢失。
}

computeXXX方法是线程安全的(和原子的!),可以防止彼此把事情搞砸。它不是完全无锁的,但比手动同步要好得多

public void record(String key, String value) {
    entries.compute(key, (k, v) -> {
        List<String> vals = v;
        if(vals == null)
            vals = new ArrayList<>();
        vals.add(value);
        return vals;
    });
}

使用
computeIfAbsent
computeIfPresent
@antoniosss,或者干脆使用
compute
。如果是Java 8+。否则,一个无锁的解决方案似乎是不可能的,因为
record
必须是原子的。@kagmole我没有为过时的Java版本提供解决方案。@Kayaman我不熟悉symbol
->
,并且读过关于
compute()
的文档。您能告诉我如何删除列表中的元素并在列表为空时删除整个列表的关键代码吗?@Hel如果您从
compute
返回
null
,它将删除映射。您可以使用类似的删除方法,使用
compute
,从列表中删除一个元素,如果列表为空,则返回null;如果列表中仍有元素,则返回列表本身。@Kayaman代码无法编译
compute()
应采用2个参数。我错过了什么吗?
public void delete(String key, String value) {
    entries.compute(key, (k, v) -> {
        List<String> vals = v;
        if(vals == null)
            return null; // No mapping, return null to keep the status quo

        vals.remove(value); // Or whatever you intend to do
        return vals.isEmpty() ? null : vals;
    });
}