ConcurrentHashMapの:条件の削除

セコ:

私が持っているConcurrentHashMapメモリ内のストレージとして使用されている(またはキャッシュは、あなたが言うかもしれません)

私は何を達成したいことはある:項目が「準備ができている」場合並行チェックし、もしそうであれば、マップから削除し(+、呼び出し元に戻します)。私はそれを行うことができます何の直接的な方法はありません。

私が思いついた唯一の解決策は、持っているItemContainerアイテムとメタデータ(両方含まれるisReadyフィールド)。アクセスごとに、私は適用する必要がありますmergeまたはcompute操作。基本的にすべてのアクセス/チェック上のオブジェクトのコンテナを交換します。

質問:

  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()それがマップにバックします。
  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();
}
ernest_k:

ConcurrentHashMapすでにあなたとの不可分性の保証を提供しますcomputeIfPresent

指定されたキーの値が存在する場合、試みがキーとその現在のマッピングされた値を指定された新しいマッピングを計算します。全体のメソッド呼び出しがアトミックに行われます。計算は短く、シンプルであるべきであり、このマップの任意の他のマッピングを更新しようとしてはならないので、計算は、進行中に、他のスレッドによってこのマップ上のいくつかの試みられ、更新操作がブロックされることがあります。

あなたはちょうどそれを使用できるように:

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ここでは、必ず返された値は、述語が(それ以外の競合状態があるかもしれない)に対してtesteddたのと同じものであることをすることです。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=279509&siteId=1