2

現在、私は HashMap を実装しています

private static Map<String, Item> cached = new HashMap<String, Item>();

Item はプロパティ Date expireTime および byte[] データを持つオブジェクトです

このマップは、複数のスレッドが同時にヒットし始めたときに使用されます。私が行うチェックは

1.

public static final byte[] getCachedData(HttpServletRequest request) throws ServletException
{
    String url = getFullURL(request);
    Map<String, Item> cache = getCache(request);  // this chec
    Item item = null;

    synchronized (cache)
    {
        item = cache.get(url);
        if (null == item)
            return null;

        // Make sure that it is not over an hour old.
        if (item.expirationTime.getTime() < System.currentTimeMillis())
        {
            cache.remove(url);
            item = null;
        }
    }

    if (null == item)
    {
        log.info("Expiring Item: " + url);
        return null;
    }

    return item.data;
}

2. データが null で返された場合は、データを作成して hashMap にキャッシュします

public static void cacheDataX(HttpServletRequest request, byte[] data, Integer minutes) throws ServletException
{
    Item item = new Item(data);
    String url = getFullURL(request);
    Map<String, Item> cache = getCache(request);

    log.info("Caching Item: " + url + " - Bytes: " + data.length);
    synchronized (cache)
    {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MINUTE, minutes);
        item.expirationTime = cal.getTime();
        cache.put(url, item);
    }
}

複数のスレッドが say キー (この場合は url) にアクセスすると、同じキーの場所でデータがキャッシュに複数回追加されるようです [ハッシュマップが最初のスレッドのデータの書き込みを終了していないため、複数のスレッドに対して getCacheData が null を返すため]

問題を解決する方法について何か提案はありますか?

4

2 に答える 2

2

cacheDataXで、追加する前に(同期されたブロック内に)アイテムの存在のチェックを追加します。

synchronized (cache)
    {
        if (cache.get(url) == null) {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MINUTE, minutes);
            item.expirationTime = cal.getTime();
            cache.put(url, item);
        }
    }

これにより、すでにルックアップを実行してnullを返した複数のスレッドが、すべて同じデータをキャッシュに追加できないようになります。キャッシュがすでに更新されているため、1つはそれを追加し、他のスレッドは黙って無視します。

于 2011-07-07T16:10:17.683 に答える
1

キャッシュからの取得とキャッシュへの挿入の両方をカバーするために、1 つの同期ブロックが必要です。コードの現状では、競合状態があります。複数のスレッドが、ステップ 2 を実行する前にステップ 1 を実行できます。

于 2011-07-07T16:05:24.617 に答える