簡體   English   中英

使用java ConcurrentHashMap實現緩存

[英]Implementing a cache using a java ConcurrentHashMap

我想在Web java應用程序中實現對重量級對象的簡單緩存。 但我無法弄清楚如何正確地做到這一點。

我錯過了什么或ConcurrentHashMap方法(putIfAbsent,...)是不夠的,需要額外的同步?

是否有更好的簡單API(在內存中,沒有外部配置)來做到這一點?

P.

除了Ken的回答之外,如果創建一個后來被扔掉的重量級對象是不可接受的(你想保證每個鍵只創建一個對象,出於某種原因),那么你可以這樣做......實際上,別。 不要自己動手。 使用google-collections (現為番石榴MapMaker類

Map<KeyType, HeavyData> cache = new MapMaker<KeyType, HeavyData>()
  .makeComputingMap(new Function<KeyType, HeavyData>() {
      public HeavyData apply(KeyType key) {
          return new HeavyData(key); // Guaranteed to be called ONCE for each key
      }
  });

然后一個簡單的cache.get(key)可以工作 ,完全免除你不必擔心並發和同步的棘手方面。

請注意,如果您想添加一些更有用的功能,例如到期,那就是

Map<....> cache = new MapMaker<....>()
  .expiration(30, TimeUnit.MINUTES)
  .makeComputingMap(.....)

如果需要,您還可以輕松地為鍵或數據使用軟值或弱值(有關詳細信息,請參閱Javadoc)

如果對於您嘗試緩存的事物臨時擁有多個實例是安全的,您可以像這樣執行“無鎖”緩存:

public Heavy instance(Object key) {
  Heavy info = infoMap.get(key);
  if ( info == null ) {
    // It's OK to construct a Heavy that ends up not being used
    info = new Heavy(key);
    Heavy putByOtherThreadJustNow = infoMap.putIfAbsent(key, info);
    if ( putByOtherThreadJustNow != null ) {
      // Some other thread "won"
      info = putByOtherThreadJustNow;
    }
    else {
      // This thread was the winner
    }
  }
  return info;
}

多個線程可以“競爭”為密鑰創建和添加項目,但只有一個應該“贏”。

您可以使用輕工廠對象來創建活動緩存,而不是將“重物”放入緩存中。

public abstract class LazyFactory implements Serializable {

  private Object _heavyObject;

  public getObject() {
    if (_heavyObject != null) return _heavyObject;
    synchronized {
      if (_heavyObject == null) _heavyObject = create();
    }
    return _heavyObject;
  }

  protected synchronized abstract Object create();
}

// here's some sample code

// create the factory, ignore negligible overhead for object creation
LazyFactory factory = new LazyFactory() {
  protected Object create() {
    // do heavy init here
    return new DbConnection();
  };
};
LazyFactory prev = map.pufIfAbsent("db", factory);
// use previous factory if available
return prev != null ? prev.getObject() : factory.getObject;

ConcurrentHashMap應該足以滿足您的需求putIfAbsent是線程安全的。

不知道你能得到多少簡單

ConcurrentMap myCache = new ConcurrentHashMap();

保羅

我意識到這是一個舊帖子,但在java 8中,這可以在不使用ConcurrentHashMap創建可能未使用的重型對象的情況下完成。

public class ConcurrentCache4<K,V> {
    public static class HeavyObject
    {
    }

    private ConcurrentHashMap<String, HeavyObject> cache = new ConcurrentHashMap<>();

    public HeavyObject get(String key)
    {
        HeavyObject heavyObject = cache.get(key);
        if (heavyObject != null) {
            return heavyObject;
        }

        return cache.computeIfAbsent(key, k -> new HeavyObject());
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM