12

高価なオブジェクトを作成し、Map. 既存の実装は次のようなものです

lock.lock()
try {
    Foo result = cache.get(key);
    if (result == null) {
        result = createFooExpensively(key);
        cache.put(key, result);
    }
    return result;
} finally {
    lock.unlock();
}

明らかにFoos、異なるkeysものを個別に作成できる場合、これは最適な設計ではありません。

私の現在のハックは、 of を使用することMapですFutures:

lock.lock();
Future<Foo> future;
try {
    future = allFutures.get(key);
    if (future == null) {
        future = executorService.submit(new Callable<Foo>() {
            public Foo call() {
                return createFooExpensively(key);
            }
        });
        allFutures.put(key, future);
    }
} finally {
    lock.unlock();
}

try {
    return future.get();
} catch (InterruptedException e) {
    throw new MyRuntimeException(e);
} catch (ExecutionException e) {
    throw new MyRuntimeException(e);
}

しかし、これは... 2つの理由から、少しハッキーに思えます:

  1. 作業は任意のプールされたスレッドで行われます。特にブロックされるので、その特定のキーを取得しようとする最初のスレッドで作業を完了していただければ幸いです。
  2. Mapが完全に入力されている場合でもFuture.get()、結果を取得するために実行します。これはかなり安いと思いますが、醜いです。

私が望むのは、そのキーが値を持つまで特定のキーの取得をブロックするが、その間は他の取得を許可するcacheに置き換えることです。そのようなものは存在しますか?または、誰かがofのよりクリーンな代替手段を持っていますか?MapMapFutures

4

3 に答える 3

2

funtom-java-utils - PerKeySynchronizedExecutorを使用できます。

キーごとにロックが作成されますが、使用されなくなるとすぐに解除されます。

また、同じキーを使用した呼び出し間でメモリの可視性を付与し、非常に高速で、異なるキーからの呼び出し間の競合を最小限に抑えるように設計されています。

クラスで宣言します。

final PerKeySynchronizedExecutor<KEY_CLASS> executor = new PerKeySynchronizedExecutor<>();

これを使って:

Foo foo = executor.execute(key, () -> createFooExpensively());
于 2016-07-17T09:04:23.137 に答える