2012-04-24 71 views
3

我有一個奇怪的(至少對我來說)具有番石榴緩存的行爲。第一次擊中後,以下訪問將返回一個空對象。我沒有使用奇怪的表現,所以我無法弄清楚我做錯了什麼。 我聲明瞭以下LoadingCache:番石榴緩存在第二次打擊時返回空結果

LoadingCache<String, Vector<Location>> locations = CacheBuilder.newBuilder() 
      .maximumSize(100000) 
      .build(
        new CacheLoader<String,Vector<Location>>() { 
         @Override 
         public Vector<Location> load(String key) { 
          return _getLocationListByTranscriptId(key); 
         } 
        }); 

,我只在該方法中使用它:

public Vector<Location> getLocationListByTranscriptId (String transcriptid) { 
    if (transcriptid.equals("TCONS_00000046")) System.out.println("tcons found, will this work?"); 
    Vector<Location> result; 
    try { 
     result = locations.get(transcriptid); 
    } catch (ExecutionException e) { 
     System.err.println("Error accessing cache, doing the hard way"); 
     result = _getLocationListByTranscriptId(transcriptid); 
    } 
    if (transcriptid.equals("TCONS_00000046")){ 
     if (result.size()==0){ 
      System.out.println("this is a problem"); 
      return null; 
     } 
     System.out.println("this is good!"); 
    } 
    return result; 
} 

遍歷集合輸入字符串中,我得到下面的輸出:

tcons found, will this work? 
this is good! 
tcons found, will this work? 
this is a problem 

所以,我第一次使用緩存,它可以工作,但是 A)該值未被正確存儲用於將來的訪問; B)價值重新設置爲一些奇怪的行爲。 我能做些什麼?感謝所有閱讀!

編輯: 感謝axtavt答案,我可以立即找出我編輯結果列表的位置。不知道爲什麼,我確信番石榴緩存會返回值的副本。感謝您的回答,並提供有關防禦性編程的建議。 (對不起,如果我不能評價你的答案呢)。

回答

4

我相信你在你的代碼中某處清楚地清除了Vector。有兩種可能性:

  • Vector由從所述高速緩存獲得它的代碼修改。

    這種錯誤可以通過使防守副本(儘管它破壞緩存的想法),或返回集合的不可變的觀點來防止:

    LoadingCache<String, List<Location>> locations = CacheBuilder.newBuilder() 
        .maximumSize(100000) 
        .build(
          new CacheLoader<String, List<Location>>() { 
           @Override 
           public List<Location> load(String key) { 
            return Collections.unmodifiableList(
             _getLocationListByTranscriptId(key)); 
           } 
          }); 
    

    更改代碼這樣一來就會很容易後發現收集地非法修改的地點。

    請注意,沒有不可修改的Vector視圖,因此應該使用List來代替。

  • _getLocationListByTranscriptId()將其結果存儲在可由其他方法(或其他方法的其他調用)訪問的字段中。所以,你應該檢查_getLocationListByTranscriptId()不會在字段中留下任何對其結果的引用。