26

永続的に保存されているオブジェクトのキャッシュを実装しています。アイデアは次のとおりです。

  • 方法getObjectFromPersistence(long id); ///Takes about 3 seconds
  • 方法getObjectFromCache(long id) //Instantly

そしてgetObject(long id)、次の擬似コードを使用したメソッドがあります。

synchronized(this){
    CustomObject result= getObjectFromCache(id)
    if (result==null){
       result=getObjectFromPersistence(id);
       addToCache(result);
    }
    return result;
}

ただし、ガベージコレクターがCustomObjectを収集できるようにする必要があります。今まで私はHashMap<Long,WeakReference<CustomObject>実装にを使用していました。問題は、時間の経過とともにHashMapが空でいっぱいになることWeakReferencesです。

WeakHashMapを確認しましたが、キーが弱い(そして値は依然として強い参照である)ため、WeakReferencesでlongを使用しても意味がありません。

この問題を解決するための最良の解決策は何ですか?「逆WeakHashMap」などはありますか?

ありがとう

4

8 に答える 8

29

これにはGuava を使用できます。MapMaker

ConcurrentMap<Long, CustomObject> graphs = new MapMaker()
   .weakValues()
   .makeMap();

makeMap()これに置き換えることで、計算部分を含めることもできます。

   .makeComputingMap(
       new Function<Long, CustomObject>() {
         public CustomObject apply(Long id) {
           return getObjectFromPersistence(id);
         }
       });

あなたが書いているものはキャッシュによく似ているので、より新しく、より専門化Cacheされた(を介して構築されたCacheBuilder)あなたにさらに関連性があるかもしれません。インターフェイスを直接実装しませんMapが、キャッシュに必要なさらに多くのコントロールを提供します。

CacheBuilderの詳細な作業方法については、これを参照できます。高速アクセスの例を次に示します。

LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
   .maximumSize(100)
   .expireAfterWrite(10, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Integer, String>() {
           @Override
           public String load(Integer id) throws Exception {
               return "value";
           }
       }
   ); 
于 2012-11-16T09:06:37.233 に答える
6

Aは、参照が収集される建設時に供給されるものにWeakReference追加されます。ReferenceQueue

キャッシュにアクセスするときはいつでも、キューに参照が見つかった場合に削除するエントリを知るためにを保持するpollことができます。ReferenceQueueHashMap<WeakReference<CustomObject>,Long>

または、キャッシュが頻繁に使用されない場合は、別のスレッドでキューを監視できます。

于 2012-11-16T09:09:34.287 に答える
4

試してみandroid.util.LruCacheましたか(SDK11クラスですが、互換性パッケージにも含まれていますandroid.support.v4.util.LruCache)。実装されていませんjava.util.Mapが、マップのように機能し、必要なメモリ量を定義でき、古い(未使用のキャッシュオブジェクト自体)をフラッシュします。

于 2012-11-16T09:10:27.363 に答える
2

あなたは「クリーンアップ」を始めることができます-時々スレッド。おそらく、マップサイズがしきい値を超えているが、せいぜい5分ごとに....そのようなものです。

主な機能を妨げないように、クリーンアップサイクルを短くしてください。

于 2012-11-16T08:59:03.290 に答える
2

jboss-commonhttp://docs.jboss.org/jbossas/javadoc/4.0.2/org/jboss/util/collection/WeakValueHashMap.java.htmlからWeakValueHashMapをテストすることもできます。

于 2014-04-17T19:02:11.693 に答える
2

最良のオプション(Guavaへの依存が望ましくない場合)は、IDを記憶するWeakReferenceのカスタムサブクラスを使用することです。これにより、クリーンアップスレッドがWeakReferencesのクリーンアップ中に弱い値を削除できるようになります。

必要なReferenceQueueとクリーンアップスレッドを含む弱参照の実装は、次のようになります。

class CustomObjectAccess {

    private static final ReferenceQueue<CustomObject> releasedCustomObjects = 
                                                                  new ReferenceQueue<>();

    static {
        Thread cleanupThread = new Thread("CustomObject cleanup thread")                  
            while (true) {
                CustomObjectWeakReference freed = (CustomObjectWeakReference) 
                                CustomObjectWeakReference.releasedCustomObjects.remove();
                cache.remove(freed.id);
            }
        };
        cleanupThread.start();
    }

    private Map<CustomObjectID, CustomObjectWeakReference> cache;

    public CustomObject get(CustomObjectID id) {
        synchronized(this){
            CustomObject result= getFromCache(id);
            if (result==null) {
                result=getObjectFromPersistence(id);
                addToCache(result);
            }
        }
        return result;
    }

    private addToCache(CustomObject co) {
        cache.put(CustomObject.getID(), new CustomObjectWeakReference(co));
    }

    private getFromCache(CustomObjectID id) {
        WeakReference<CustomObject> weak = cache.get(id);
        if (weak != null) {
            return weak.get();
        }
        return null;
    }

    class CustomObjectWeakReference extends WeakReference<CustomObject> {

        private final CustomObjectID id;

        CustomObjectWeakReference(CustomObject co) {
            super(co, releasedCustomObjects);
            this.id = co.getID();
        }
    }
}
于 2015-11-13T23:13:04.213 に答える
0

タグ付けされた弱いオブジェクトを保存する必要があり、を使用する代わりに計算しました。代わりに使用WeakHashMap<String, T>することができましWeakHashMap<T, String>た。

これはKotlinですが、Javaにも同様に適用する必要があります。

abstract class InstanceFactory<T> {
    @Volatile
    private var instances: MutableMap<T, String> = WeakHashMap<T, String>()

    protected fun getOrCreate(tag: String = SINGLETON, creator: () -> T): T =
        findByTag(tag)?.let {
            it
        } ?: synchronized(this) {
            findByTag(tag)?.let {
                it
            } ?: run {
                creator().also {
                    instances[it] = tag
                }
            }
        }

    private fun findByTag(tag: String): T? = instances.entries.find { it.value == tag }?.key

    companion object {
        const val SINGLETON = "singleton"
    }
}

これは次のように使用できます。

class Thing(private val dependency: Dep) { ... }

class ThingFactory(private val dependency: Dep) : InstanceFactory<Thing>() {

    createInstance(tag: String): Thing = getOrCreate(tag) { Thing(dependency) }

}

単純なシングルトンは次のように実行できます。

object ThingFactory {
    getInstance(dependency: Dependency): Thing = getOrCreate { Thing(dependency) }
}
于 2018-11-01T09:40:42.513 に答える
0

Apache Commons CollectionsにはReferenceMapがあります。これは、ハードキーとソフト値(WeakHashMapの反対)を使用したマップ実装です。

于 2021-03-17T13:03:52.143 に答える