使用java ConcurrentHashMap实现缓存

使用java ConcurrentHashMap实现缓存,java,concurrency,concurrenthashmap,Java,Concurrency,Concurrenthashmap,我想在web java应用程序中实现一个简单的重量级对象缓存。但我不知道该怎么做 我是否遗漏了什么,或者ConcurrentHashMap方法(putIfAbsent,…)不够,需要额外的同步 是否有更好的简单API(内存存储,无外部配置)来实现这一点 p.ConcurrentHashMap应该足以满足您的需要,因为它是线程安全的 不知道你能得到多简单 ConcurrentMap myCache = new ConcurrentHashMap(); Paul您可以使用轻工厂对象创建活动缓存,而

我想在web java应用程序中实现一个简单的重量级对象缓存。但我不知道该怎么做

我是否遗漏了什么,或者ConcurrentHashMap方法(putIfAbsent,…)不够,需要额外的同步

是否有更好的简单API(内存存储,无外部配置)来实现这一点


p.

ConcurrentHashMap应该足以满足您的需要,因为它是线程安全的

不知道你能得到多简单

ConcurrentMap myCache = new ConcurrentHashMap();
Paul

您可以使用轻工厂对象创建活动缓存,而不是将“重对象”放入缓存

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;

如果您尝试缓存的对象暂时有多个实例是安全的,则可以执行如下“无锁”缓存:

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;
}

多个线程可以“竞相”为密钥创建和添加一个项目,但只有一个线程应该“获胜”。

根据Ken的回答,如果创建一个后来被丢弃的重量级对象是不可接受的(出于某种原因,您想保证每个密钥只创建一个对象),那么您可以通过。。。。事实上,不要。不要自己做。使用(现在):


如果需要,您还可以轻松地对键或数据使用软值或弱值(更多详细信息,请参阅Javadoc)

我知道这是一篇老文章,但在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());
    }
}
公共类ConcurrentCache4{
公共静态类重对象
{
}
私有ConcurrentHashMap缓存=新ConcurrentHashMap();
公共重对象获取(字符串键)
{
HeavyObject HeavyObject=cache.get(键);
if(heavyObject!=null){
返回重对象;
}
返回cache.computeIfAbsent(key,k->newHeavyObject());
}
}

如果您希望有一个更新方法来替换/刷新给定密钥的重对象,或者只使用MapMaker,并且只有一个线程会创建重对象,该怎么办。如果另一个线程需要它,而它仍然在创建它的中间,它将只是等待结果。@ Paolo:我将让向下投票<代码> MAPMAGER < /代码> GurUS回答这个问题。只是想知道:您对缓存的真正要求是什么?是否需要缓存重载对象的完整可传递闭包,以便它在应用程序服务器集群中保持一致?如果是这样的话,这是一个需要解决的非常重要的问题,您最好使用像ehcache这样的缓存库。哇,这是一个多么漂亮和优雅的解决方案啊!
Map<....> cache = new MapMaker<....>()
  .expiration(30, TimeUnit.MINUTES)
  .makeComputingMap(.....)
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());
    }
}