0

しばらく前にソフト参照を使用してキャッシュを作成しましたが、バグを解決しようとすると、実際には間違って実行され、必要のないときにオブジェクトが削除されるのではないかと心配しています。これは私がそれをした方法です:

private static final Map<String, SoftReference<Buffered>> imageMap =
        new HashMap<String,SoftReference<Buffered>>();

public static synchronized Buffered addImage(String sum, final byte[] imageData)
    {
        SoftReference<Buffered> bufferedRef = imageMap.get(sum);
        Buffered buffered;
        if (bufferedRef!=null)
        {
            //There are no longer any hard refs but we need again so add back in
            if(bufferedRef.get()==null)
            {
                buffered = new Buffered(imageData, sum);
                imageMap.put(sum, new SoftReference(buffered));
            }
            else
            {
                buffered=bufferedRef.get();
            }
        }
        else
        {
            buffered = new Buffered(imageData, logDescriptor, sum);
            imageMap.put(sum, new SoftReference(buffered));
        }
        return buffered;
    }

    public static Buffered getImage(String sum)
{           
    SoftReference<Buffered> sr = imageMap.get(sum);
    if(sr!=null)
    {
        return sr.get();
    }
    return null;
}

つまり、呼び出しプロセスは、キーの合計によって識別/検索できる新しいバッファリングされたオブジェクトを追加できます。このバッファリングされたオブジェクトが少なくとも1つのオブジェクトによって使用されている限り、マップから削除されることはありませんが、オブジェクトによって使用されなくなった場合、メモリが不足するとガベージコレクションになる可能性があります。

しかし、今私のコードを見ることが重要なことは、キーフィールドの合計が常にどこか別の場所で参照されていることです(必ずしもそうではありません)。

編集:それで私はコリンの解決策を試しましたが、putIfAbsent()が付加価値を返さないようであるため、私はちょっと困惑しています。addImageメソッドを変更してデバッグを取得しました

public static synchronized Buffered addImage(String sum, final byte[] imageData)
    {
        Buffered buffered = new Buffered(imageData, sum);
        Buffered buffered2 =  imageMap.get(sum );
        Buffered buffered3 =  imageMap.putIfAbsent(sum,buffered );
        Buffered buffered4 =  imageMap.get(sum );
        System.out.println("Buffered AddImage1:"+buffered);
        System.out.println("Buffered AddImage2:"+buffered2);
        System.out.println("Buffered AddImage3:"+buffered3);
        System.out.println("Buffered AddImage4:"+buffered4);                
        return buffered2;
    }

戻り値

Buffered AddImage1:com.Buffered@6ef725a6
Buffered AddImage2:null
Buffered AddImage3:null
Buffered AddImage4:com.Buffered@6ef725a6

したがって、Bufferedインスタンスが最初から存在せず、正常に構築および追加されたことを明確に示していますが、putIfAbsentによって返される必要がありますか?

4

2 に答える 2

2

自分で行うのではなく、 GuavaMapMakerを使用することをお勧めします。

private static final ConcurrentMap<String, Buffered> imageMap = 
    new MapMaker().softValues().makeMap();

public static Buffered addImage(String sum, final byte[] imageData) {
  Buffered buffered = new Buffered(imageData, sum);
  Buffered inMap = imageMap.putIfAbsent(sum, buffered);
  return inMap != null ? inMap : buffered;
}

public static Buffered getImage(String sum) {           
  return imageMap.get(sum);
}

これはとConcurrentMapを使用するため、のインスタンスの作成に費用がかかる場合を除いputIfAbsentて、同期する必要はありません。これは、コードとは異なり、値がガベージコレクションされたときに実際にマップからエントリを削除することも処理します。addImageBuffered

編集:呼び出して結果getImageを取得nullした場合(おそらく値がガベージコレクションされたため)、どうしますか?キーbyte[]に基づいて画像データを取得する方法はありますか?sumその場合は、のインスタンスを作成するプロセスをカプセル化することをお勧めBufferedsumますFunction<String, Buffered>。これにより、通常のマップの代わりにコンピューティングマップを使用できます。

private static final ConcurrentMap<String, Buffered> imageMap = new MapMaker()
    .softValues()
    .createComputingMap(getBufferedForSumFunction());

このようにすると、addImageメソッドも必要ない場合があります...getマップ上でが呼び出され、指定されたエントリがない場合はsum、関数を呼び出し、結果をキャッシュして返します。

于 2010-11-17T21:19:39.687 に答える
1

データがどこにも参照されていないときにデータがガベージコレクションを取得できるようにするだけの場合は、WeakHashMapを使用します。

マップでデータが使用できなくなった場合に実際にデータを再作成できるようにする場合は、getImage()を変更して、参照が使用可能かどうかを確認し、使用できない場合は再作成する必要があります。

あなたが欲しいのは前者のようです。

ソフト参照と弱参照の違いは、ガベージコレクターがアルゴリズムを使用して、ソフト到達可能なオブジェクトを再利用するかどうかを決定しますが、常に弱到達可能オブジェクトを再利用することです。(参照)

于 2010-11-17T21:04:10.820 に答える