java - 并发HashMap : remove on condition

标签 java multithreading caching data-structures thread-safety

我有一个 ConcurrentHashMap,它用作内存存储(或者你可能会说的缓存)

我想要实现的是:同时检查一个项目是否“准备好”,如果是,则将其从 map 中删除(+将其返回给调用者)。没有直接的方法可以让我做到这一点。

我想到的唯一解决方案是拥有一个 ItemContainer,它将包含项目和元数据(isReady 字段)。每次访问时,我都必须应用合并计算操作。本质上是在每次访问/检查时替换对象的容器。

问题:

  1. 我的解决方案看起来合理吗?
  2. 是否有任何优秀的库可以实现类似的功能?

我根据要求添加了“样板”代码:

public class Main {

    public static void main(String[] args) {
        Storage storage = new Storage();
        storage.put("1", new Record("s", 100));
        storage.put("2", new Record("s", 4));
        storage.removeIf("1", Main::isReady);
    }

    public static boolean isReady(Record record) {
        return record.i > 42;
    }

    public static class Record {

        public Record(String s, Integer i) {
            this.s = s;
            this.i = i;
        }

        String s;
        Integer i;
    }

    public static class Storage {
        ConcurrentHashMap<String, Record> storage = new ConcurrentHashMap<>();

        public void put(String key, Record record) {
            storage.put(key, record);
        }

        public Record removeIf(String key, Function<Record, Boolean> condition) {
            return null; // TODO: implement
        }
    }
}

其他解决方案(需要权衡):

  1. 始终remove()检查,然后merge()将其返回到 map 。
  2. 使用具有合理的项目疏散策略(即 LRU)的缓存,并仅检查疏散的项目。

基于@ernest_k解决方案:

public Record removeIf(String key, Predicate<Record> condition) {
    AtomicReference<Record> existing = new AtomicReference<>();

    this.storage.computeIfPresent(key, (k, v) -> {
        boolean conditionSatisfied = condition.test(v);

        if (conditionSatisfied) {
            existing.set(v);
            return null;
        } else {
            existing.set(null);
            return v;
        }
    });

    return existing.get();
}

最佳答案

ConcurrentHashMap computeIfPresent 已经为您提供了原子性保证.

If the value for the specified key is present, attempts to compute a new mapping given the key and its current mapped value. The entire method invocation is performed atomically. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.

所以你可以使用它:

public Record removeIf(String key, Predicate<Record> condition) {

    AtomicReference<Record> existing = new AtomicReference<>();

    this.storage.computeIfPresent(key, (k, v) -> {
        existing.set(v);
        return condition.test(v) ? null : v;
    });

    return existing.get();
}

请注意,我使用了 Predicate<Record>因为它应该优先于 Function<Record, Boolean> .

将当前值存储在 AtomicReference 中的原因这是为了确保返回的值与测试谓词的值相同(否则可能存在竞争条件)。

关于java - 并发HashMap : remove on condition,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55815797/

相关文章:

linux - 在 ramdisk 上缓存 - 查找要删除的最旧文件

java - 如何使用 "LIKE"和 "%"检查 android 中变量的相似性(Java 代码)

java - "final"在运行时是最终的吗?

java - 如何线程安全地读取和写入数据库?

iOS 应用 : When should I clear my cache data?(使用 Realm)

javascript - 禁用浏览器缓存

java - 使用 Ldap 对 Glassfish 进行基本身份验证

java - 如何解释分析结果?

c++ - 在命名空间 std 中找不到 GCC std::thread

java多线程isalive与否