繁体   English   中英

将值放入Google番石榴loadingCache

[英]Putting a value in a google guava loadingCache

这是我的加载缓存定义:

  private class ProductValue {
      private long regionAValue;
      private long regionBValue;

      // constructor and general stuff here
  }

  private final LoadingCache<ProductId, ProductValue> productCache = CacheBuilder.newBuilder()
            .expireAfterAccess(4, TimeUnit.MINUTES)
            .build(new CacheLoader<ProductId, ProductValue>() {
                @Override
                public ProductValue load(final ProductId productId) throws Exception {
                    return updateProductValues(productId);
                }
            });

  private ProductValue updateProductValues(final ProductId productId) {
     // Read from disk and return
  }

现在,我有一个用例,需要在高速缓存中设置regionA或regionB的值,直到下一次更新发生为止。 我对自己所具有的逻辑的并发含义感到困惑:

  public void setProductValue(final ProductId productId, final boolean isTypeA, final long newValue) throws ExecutionException {

    ProductValue existingValues = productCache.get(productId);   // 1
    if (isTypeA) {
        existingValues.regionAValue = newValue;
    } else {
        existingValues.regionBValue = newValue;
    }

    productCache.put(productId, existingValues);                  // 2
}

1我只是读取了给定密钥存储在缓存中的信息的引用,此get是线程安全的,因为加载缓存的行为类似于并发映射。 但是在12之间,此引用可以被其他一些线程覆盖。 由于我已经使用缓存中已经存在的引用覆盖了“值”,因此是否需要将键值对放入缓存中? 我是否需要行2

(免责声明:我不是Guava Cache专家)

我认为您的代码中存在两个并发问题:

  1. 您可以通过两种操作来对现存值中的对象进行突变,这是existingValues.regionAValue = ...existingValues.regionAValue = ...existingValues.setRegionValue(...) 当仅应用一个操作时,其他线程可以看到状态。 我认为这是不想要的。 (正确?)
  2. get()put()该值可能会再次加载到缓存中,而put()覆盖一个新值。

关于1:

如果对对象的读取多于写入,那么一个好的选择是使用不可变的对象。 您无需触摸实例,但可以复制原始对象,进行变异,然后将新对象放入缓存中。 这样,只有最终状态才可见。

关于2:

原子CAS操作可以为您提供帮助(例如,兼容JSR107的缓存)。 有用的方法是布尔值替换(K键,V oldValue,V newValue);

在Google Guava中,可以通过ConcurrentMap接口访问CAS方法,您可以通过asMap()进行检索。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM