2014-10-29 141 views
0

這是我的加載緩存的定義把一個值:在谷歌番石榴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 
    } 

現在,我已經在那裏我需要設置地域性或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我剛纔讀的存儲在緩存中給定的密鑰信息的參考,這得到的是線程安全的,因爲加載緩存的作用就像一個併發地圖。但是在12之間,此引用可以被其他某個線程覆蓋。由於我使用緩存中已存在的引用覆蓋了「值」,因此是否需要將鍵值對放入緩存中?我需要行2

+0

是的,其他線程可以在1之後但在2或3之前訪問和修改緩存。 – 2014-10-29 04:46:01

+0

請參閱編輯。 – user1071840 2014-10-29 11:29:37

回答

1

(免責聲明:我不是一個番石榴緩存專家)

我認爲你必須在你的代碼中有兩處併發問題:

  1. 您有變異在existingValues對象兩種操作,即existingValues.regionAValue = ...existingValues.setRegionValue(...)。其他線程只能應用一個操作時才能看到狀態。我認爲那不是想要的。 (正確?)
  2. get()put()之間,該值可能會再次加載到緩存中,並且put()將覆蓋新值。

關於1:

如果你有更多的閱讀對象,然後寫道,一個很好的選擇是使用不可變對象。您不會觸及實例,而是執行原始對象的副本,進行變異,然後將新對象放入緩存中。這樣只有最終狀態變得可見。

關於2:

原子的CAS操作可以幫助你在這裏(如JSR107兼容高速緩存)。有用的方法是boolean replace(K key, V oldValue, V newValue);

在Google Guava中,CAS方法可以通過ConcurrentMap接口訪問,您可以通過asMap()來檢索。

+0

對不起,我修復了這個錯誤。只有'1'和'2'操作。我有一個非常愚蠢的問題,那就是,因爲我已經使用引用「existingValues」更新了值,我是否需要將它放回緩存中?我可以在緩存定義中使用AtomicReference嗎? – user1071840 2014-10-29 11:27:47

+0

Guava Cache在內存中,因此通過引用存儲。這意味着你實際上不需要把它放回去。 – cruftex 2014-10-29 11:40:25

+0

很酷。在比賽中,只要'puts'和'sets'是原子的,我就不關心完成順序。所以看起來我需要做的就是將類ProductValue的'long'改爲'AtomicLong'。我對麼? – user1071840 2014-10-29 11:51:15