0

次のようなコードがあるとします。

public final class SomeClass
{
    private final Map<SomeKey, SomeValue> map = new HashMap<SomeKey, SomeValue>();

    // ...

    public SomeValue getFromCache(final SomeKey key)
    {
        SomeKey ret;
        synchronized(map) {
            ret = map.get(key);
            if (ret == null) {
                ret = buildValue(key);
                map.put(key, ret);
            }
        }
        return ret;
    }

 //etc
 }

問題はパフォーマンスです。buildValue()が高価な関数である場合、その値を構築する必要がある 1 つの呼び出し元が、値が既に存在する可能性のある他のすべての呼び出し元をブロックします。値を構築する必要がある呼び出し元が他の呼び出し元をブロックしないメカニズムを見つけたいと思います。

この問題がまだ取り組まれていない (そして解決されていない) とは信じられません。解決策をグーグルで検索しようとしましたが、これまでのところ見つかりませんでした。それを行うためのリンクはありますか?

を使おうと思っていたのReentrantReadWriteLockですが、まだ何も付いていません。

4

3 に答える 3

1

問題の一部は、あなたが持っている get メソッドが同期しているように見えることだと思います。それだけで、非同期で何かを行うのが難しくなります。get はコールバックを受け取る必要があるようです。

Java Concurrency in Practice book では、ConcurrentHashMap と FutureTasks を使用した優れたキャッシュについて詳しく説明しています。http ://jcip.net/listings/Memoizer.javaをご覧ください。

ただし、そのクラスを微調整して非同期にする必要があります。タスクが計算されるときに現在のスレッドをブロックしますが、2 つのスレッドが同じことを計算するのを防ぎます。1 つのスレッドが既にそれを計算していて、別のスレッドがそれを望んでいる場合、新しい計算を開始するのではなく、計算が終了するまで待機します。

于 2012-06-17T15:24:09.660 に答える
1

Guavaはこれに対する非常に堅実な解決策を持っていjava.util.concurrentます。(開示: 私は Guava に貢献していますが、キャッシュにはまったく取り組んでいません。)

Guava のCacheパッケージに関するユーザー ガイドの記事はこちらですが、構文は次のようになります...

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .maximumSize(1000)
   .expireAfterWrite(10, TimeUnit.MINUTES)
   .removalListener(MY_LISTENER)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) throws AnyException {
           return createExpensiveGraph(key);
         }
       });
于 2012-06-17T15:49:26.953 に答える
0

ReentrantReadWriteLock は解決策になる可能性があります。マップからデータを取得するときは読み取りロックを使用し、データを構築してマップに入れるときは書き込みロックを使用します。このソリューションの欠点は、書き込みロックがマップ全体をロックするため、buildValue が同期メソッドになることです。マップに書き込むキャッシュが多すぎると、それらを 1 つずつ書き込む必要があります。

別の方法はjava.util.concurrent.ConcurrentMapを使用することです。データをマップに入れるときにputIfAbsentを使用してロックする必要はありません。欠点は、同じキーを持つデータが異なるスレッドで同時に構築される可能性があることですが、アプリケーションが厳密なメモリ使用を必要としない限り、問題にはなりません。

于 2012-06-17T16:11:01.107 に答える